//============================================================================================
/**
 * @file	pkthln_shot.c
 * @brief 	サッカー
 * @author	Nozomu Saito
 */
//============================================================================================
#include "pkthln_shot_local.h"
#include "pkthln_shot.h"
#include "../../pkthln_obj_common.h"
#include "../../poke_clact.h"
#include "../pkthln_clact.h"
#include "../pkthln_act_def.h"

#include "system/snd_tool.h"
#include "system/wipe.h"
#include "system/render_oam.h"
#include "system/fontproc.h"
#include "gflib/touchpanel.h"

#include "../../pkthln_comm_pack.h"
#include "../../poke_clact_move.h"

#include "../event_se_def.h"

#include "system/arc_util.h"

#include "shot_comm.h"
#include "shot_obj_pri.h"

#include "../../cmn_res.h"
#include "../../pkthln_poke_act.h"

#include "shot_ai.h"

#include "pkthln_shot_sub.h"

//成績作成用
#include "system/msgdata_util.h"
#include "msgdata/msg.naix"
#include "msgdata/msg_pokethlon.h"

#include "../pkthln_evt_info.naix"
#include "pkthev_shot.naix"

#include "communication/wm_icon.h"

// 構造体が想定のサイズとなっているかチェック
#ifdef PM_DEBUG
#ifdef _NITRO
SDK_COMPILER_ASSERT(sizeof(SHOT_PARENT_DATA) == 36);
#endif
extern DEBUG_PKTHLN_WORK DebugPkthlnWk;
#endif		//PM_DEBUG

//デバッグ機能
#ifdef PM_DEBUG
//#define DEBUG_MIN_TIME			//デバッグ短縮時間
#endif



#define SHOT_HEAP_SIZE	(0x50000)

#define PCLACT_TCB_PRIORITY	(0)

#define POKE_L_SIZE		(64)
#define POKE_S_SIZE		(32)

#define GPOST_NUM	(2)
#define DASH_EFF_WAIT	(5)

#define SHOT_MAIN_PALETTE_NUM	(2)
#define SHOT_SUB_PALETTE_NUM	(1)
#define COUNT_PALETTE_NUM	(1)

#define SUB_ACT	( 1 + TIMER_ACT_NUM + 1 )		//時計1+タイマー3桁+旗1
#define SUB_DISP_PAL_NUM	(SHOT_SUB_PALETTE_NUM)	//サブ画面ＯＢＪ
#define ACT_MAX	(1+1+1+4*SHOT_EVENT_POKE_NUM + (DASH_EFF_NUM*SHOT_EVENT_POKE_NUM) + 2*BALL_MAX + ((1+GPOST_NUM+1+1)*ENTRY_MEMBER_NUM_MAX)+(2*ENTRY_MAX) +SUB_ACT)
//カウントダウン+ラストカウント+ニューレコード+ポケ12+ガイド12+影12+汗orヒヨコ12+ダッシュエフェクト3ｘ12 + (ボール+エフェクト)ｘ2 + (ゴール1+ゴールポスト2+自分ゴールエフェクト+ポストフラッシュ) x 4 + (▼マーカ+ペン)*3 +サブ画面ACT
#define SHOT_EVENT_OBJ_NUM	(SHOT_EVENT_POKE_NUM + ACT_MAX )
#define SHOT_EVENT_PAL_NUM	(SHOT_EVENT_POKE_NUM+ 1 + 1 + 1 + SUB_DISP_PAL_NUM)	//ポケ12+共有リソース+リング+汗+サブ画面

#define ONE_SEC	(30)

#define DATA_NONE	(0xff)

#define RECOV_VAL	(2)		//スタミナ回復値
#define FATIGUE_COUNT	(60)

#define BALL_MV_FRAME	(30)

#define ATTACK_SPEED	(6*FX32_ONE)

#ifdef DEBUG_MIN_TIME
#define GAME_TIME		(30)		//デバッグ短縮ゲーム時間
#else
#define GAME_TIME	(90*30)		//ゲーム時間
#endif

#define PANIC_TIME	(3*30)
#define FATIGUE_VAL	(30)

#define SHOT_SCORE_MAX	(99)	//ゲーム得点最大(ゴールによる点数)
#define RSULT_SCORE_MAX	(100+SHOT_SCORE_MAX)	//ゲーム得点最大(リザルト表示時)

#define KNOCKBACK_VAL_ATTACK	(3)
#define KNOCKBACK_VAL_GARD		(3)
#define KNOCKBACK_VAL_DAMAGE	(7)

#define HOLD_TIME_MAX	(20)
#define HOLD_DASH_TIME	(8)			//ダッシュ状態になるベタタッチ最大時間

#define BALL_GENE_POS_NUM	(15)
#define START_BALL_GENE_POS_IDX	(7)
#define BALL_APP_COUNT	(8)

#define FREEZE_TIME 	(30)
#define GARD_FREEZE_TIME 	(15)
//ＢＭＰ関連
#define	SHOT_FONT_PAL	(14)
#define	REC_FONT_PAL	(15)
#define WIN_CGX_BASE	(1)
#define WIN_REC_CGX	(WIN_CGX_BASE)
#define REC_BG	(GF_BGL_FRAME3_M)
#define NAME_BG	(GF_BGL_FRAME0_M)

#define WIN_NAME1_PX	(0)
#define WIN_NAME2_PX	(8)
#define WIN_NAME3_PX	(16)
#define WIN_NAME4_PX	(24)
#define WIN_NAME_PY		(0)
#define WIN_NAME_SX		(8)
#define WIN_NAME_SY		(2)

#define WIN_NAME1_CGX	(1/*WIN_REC_CGX+(WIN_REC_SX*WIN_REC_SY)*/)
#define WIN_NAME2_CGX	(WIN_NAME1_CGX+(WIN_NAME_SX*WIN_NAME_SY))
#define WIN_NAME3_CGX	(WIN_NAME2_CGX+(WIN_NAME_SX*WIN_NAME_SY))
#define WIN_NAME4_CGX	(WIN_NAME3_CGX+(WIN_NAME_SX*WIN_NAME_SY))

#define	COL_N_WHITE			( GF_PRINTCOLOR_MAKE( 15, 14, 0 ) )		// フォントカラー：白
#define	COL_SHOT_WHITE		( GF_PRINTCOLOR_MAKE( 1, 2, 0 ) )		// フォントカラー：白(通常)
#define	COL_SHOT_ORANGE		( GF_PRINTCOLOR_MAKE( 3, 4, 0 ) )		// フォントカラー：オレンジ(トップのプレーヤー用)
//ゴールセルデータ座標
#define GOAL1_X		( (4*8) * FX32_ONE )
#define GOAL1_Y		( (2*8+4*8) * FX32_ONE )
#define GOAL2_X		( (24*8+4*8) * FX32_ONE )
#define GOAL2_Y		( (2*8+4*8) * FX32_ONE )
#define GOAL3_X		( (4*8) * FX32_ONE )
#define GOAL3_Y		( (2*8+14*8+4*8) * FX32_ONE )
#define GOAL4_X		( (24*8+4*8) * FX32_ONE )
#define GOAL4_Y		( (2*8+14*8+4*8) * FX32_ONE )

#define GPOST1_X	( 8*1*FX32_ONE )
#define GPOST2_X	( 8*8*FX32_ONE )
#define GPOST3_X	( 24*8*FX32_ONE )
#define GPOST4_X	( 31*8*FX32_ONE )
#define GPOST1_Y	( (8*2+8*1)*FX32_ONE )
#define GPOST2_Y	( (8*2+8*8)*FX32_ONE )
#define GPOST3_Y	( (8*2+8*14)*FX32_ONE )
#define GPOST4_Y	( (8*2+8*21)*FX32_ONE )

//ゴールライン座標
#define G1_X	( 8*0 )
#define G2_X	( 8*8 )
#define G3_X	( 24*8 )
#define G4_X	( 32*8 )
#define G1_Y	( (8*2+8*0) )
#define G2_Y	( (8*2+8*8) )
#define G3_Y	( (8*2+8*14) )
#define G4_Y	( (8*2+8*22) )

//ゴールライン座標当たり判定用
#define H_G1_X	( (8*0) - (8*4) )
#define H_G2_X	( (8*8) + (8*4) )
#define H_G3_X	( (24*8) - (8*4) )
#define H_G4_X	( (32*8) + (8*4) )
#define H_G1_Y	( (8*2+8*0) - (8*4) )
#define H_G2_Y	( (8*2+8*8) + (8*4) )
#define H_G3_Y	( (8*2+8*14) - (8*4) )
#define H_G4_Y	( (8*2+8*22) + (8*4) )

#define GPOST_RANGE	(8)
#define GOAL_COUNT_MAX	(10)		//この間はゴールとみなす

#define WALL_MIN_X	(8)
#define WALL_MAX_X	(247)
#define WALL_MIN_Y	(16)
#define WALL_MAX_Y	(183)

//金玉出現タイム
#define GOLD_BALL_TIME1	(40*30)
#define GOLD_BALL_TIME2	(20*30)
#define GOLD_BALL_TIME3	(10*30)

#define GOLD_BALL_PROB1	(0)
#define GOLD_BALL_PROB2	(5)
#define GOLD_BALL_PROB3	(10)
#define GOLD_BALL_PROB4	(25)

#define TWO_BALL_TIME	(30*30)

//ゴール演出
#define GOAL_EFF_FRAME	(30)	//ゴール演出フレーム
#define GOAL_EFF_TCB_PRI	(1)

//この競技のボールY座標の特別な使いかたをするための定義
#define BALL_FIELD	(192) 	///この値未満のときはフィールドでボールが動いている
#define BALL_BOUND	(216)	///この値未満のときは、ボールがフィールドに出現するアニメが進行中である
#define BALL_GOAL	(232)	///この値未満のときは、ボールがゴールしていてゴールアニメが進行中である
//ゴール演出用ボールＹ座標
#define GOAL_EFF_BASE_Y1	(216)
#define GOAL_EFF_BASE_Y2	(220)
#define GOAL_EFF_BASE_Y3	(224)
#define GOAL_EFF_BASE_Y4	(228)

#define MY_GOAL_ANM_OFS		(17)
#define POST_FLASH_ANM_OFS	(19)


#define PAL_CHG_OFS	(8)		//キャラ
#define PAL_CHG_W	(8)		//キャラ
#define PAL_CHG_H	(2)		//キャラ
#define FLASH_MARGINE	(5)

#define TOP_NON_DISP_TIME	(10*30)		//トップ表示を行わない残り時間

#define SORT_POKE_MAX		(ENTRY_MAX*(ENTRY_MEMBER_NUM_MAX-1))	//自分以外のチームのポケ数
#define POKE_SORT_BUF_SIZE	(40)
//Nitro関数MATH_QSortを使用する際のソート作業領域
//必要サイズは、マニュアルによると (Log2(num)+1) * 8 byte
//今回ソートするポケ数はSORT_POKE_MAX = 9 なので
//Log2(9)+1 * 8 < Log2(16)+1 *8 = (4+1)*8 = 40 byte 用意しとく

//ポケと影とマーカーのプライオリティ間隔	ポケと影の間にボールが入るようになればOK
#define PRI_MARGINE	(20)

enum{
	BG_PAL_FIELD = 0,
	BG_PAL_FRAME,
	BG_PAL_PLUS,
	BG_PAL_MINUS,
};

enum{
	GOAL_EFF_WAIT,
	GOAL_EFF_START,
	GOAL_EFF_FLASH,
};

typedef enum{
	GOAL_NONE,
	GOAL_GOLD,
	GOAL_NORMAL,
	GOAL_MINUS,
}GOAL_TYPE;

typedef enum {
	HIT_NONE,
	HIT_L,		//左壁
	HIT_R,		//右壁
	HIT_U,		//上壁
	HIT_D,		//下壁
	HIT_G_LU,	//左上ゴールライン
	HIT_G_RU,	//右上ゴールライン
	HIT_G_LD,	//左下ゴールライン
	HIT_G_RD,	//右下ゴールライン
}HIT_CHECK;

typedef struct SHOT_PARAM_tag
{
	int ShotR[5];
	int GardR[5];
	int Stamina[5];
	int SpdW[5];
	int SpdD[5];
	int ShotPw[5];
}SHOT_PARAM;

typedef struct POS_DATA_tag
{
	u16 X;
	u16 Y;
}POS_DATA;

typedef struct GOAL_EFF_tag
{
	u8 Seq;
	u8 NetID;
	u8 Counter;
	s8 BallIdx;
	TCB_PTR GoalEffTcbPtr;
	PKTHLN_SHOT_PTR ptr;
	u8 FlshCnt;
	u8 PalNo;		//0〜1
	u8 IsPlus;
	u8 IsGold;
}GOAL_EFF;

typedef struct PKTHLN_SHOT_tag
{
	//アクター
	PKTHLN_CLACT_CNT_PTR ActCntPtr;
	GF_BGL_INI *bgl;
	GF_BGL_BMPWIN	Win;			// BMPウィンドウデータ
	GF_BGL_BMPWIN	NameWin[ENTRY_MEMBER_NUM_MAX];
	int HeapID;
	SHOT_POKE	Poke[ENTRY_MEMBER_NUM_MAX][ENTRY_MAX];
	SHOT_BALL	Ball[BALL_MAX];
	PKTHLN_ACT_PTR	GoalActPtr[ENTRY_MEMBER_NUM_MAX];
	PKTHLN_ACT_PTR	MyGoalActPtr[ENTRY_MEMBER_NUM_MAX];
	PKTHLN_ACT_PTR	PostFlashActPtr[ENTRY_MEMBER_NUM_MAX];
	int TotalScore[ENTRY_MEMBER_NUM_MAX];

	TP_STATE	TpState[ENTRY_MEMBER_NUM_MAX];		//親が使う
	u8 HoldPokeNo[ENTRY_MEMBER_NUM_MAX];			//親が使う

	int Timer;

	u8 SendNetID;									//親が使う
	u8 CommTime;			//通信する時間データ10シンクで1カウントアップ　0から45、46
	u8 EndFlg;
	u8 AddScoreReq;

	u8 CalcScoreCallWait;
	u8 SendPointUpTeamIdx;
	u8 HoldTime;
	u8 GoldProbPlus;		//足しこむ金玉出現率

	CMN_RES_CNT_PTR	CmnResCntPtr;
	POKE_ACT_CNT_PTR PokeActCntPtr;

	SHOT_AI_CONT_PTR AICntPtr;
	SHOT_SUB_DISP_CNT_PTR SubDispCntPtr;

	VecFx32 BallBaseDir[8];

	u8 BallAppSeFlg[BALL_MAX];
	u8 dummy[2];

	STRBUF * GoalStr;
	STRBUF * Goal2Str;
	STRBUF * LostStr;
	STRBUF * PlayerStr[ENTRY_MEMBER_NUM_MAX];

	GOAL_EFF GoalEff[ENTRY_MEMBER_NUM_MAX];

	u8 ScoreStoc[ENTRY_MEMBER_NUM_MAX];
	u8 TopFlg[ENTRY_MEMBER_NUM_MAX];

	u8 *PokeSortBuf;
}PKTHLN_SHOT;

typedef struct POKE_SORT_WORK_tag
{
	u16 Idx;
	u16 Y;
}POKE_SORT_WORK;

static void SetVramBank(void);

static BOOL SHOT_Func_Phase1(PKTHLN_PTR work, u8 *seq);
static BOOL SHOT_Func_Phase2(PKTHLN_PTR work, u8 *seq);


static void SetPokeRectHitTable(RECT_HIT_TBL *rect, int x, int y, int sizx, int sizy);

static void BgInit(GF_BGL_INI * ini);
static void SetGraphic(PKTHLN_SHOT_PTR ptr);
static void CreateBmpWin(PKTHLN_SHOT_PTR ptr);

static BOOL ControlMain(PKTHLN_PTR work);
static void SetDraw(PKTHLN_PTR work);
static void CommMain(PKTHLN_PTR work);
static void MovePoke(PKTHLN_PTR work);

static void SetCommInfo(PKTHLN_SHOT_PTR ptr, SHOT_PARENT_DATA *parent);
static void SetGoalAnm(	PKTHLN_SHOT_PTR ptr, const u8 inBallIdx, const BOOL inIsGold,
						const u8 inX, const u8 inY, const u8 inMyNetID);
static void GetLastPoint(const u8 inTpX, const u8 inTpY, VecFx32 *outPoint);

static void UpdataSubDispScore(PKTHLN_PTR work);

static u8 CheckPokeTouch(PKTHLN_SHOT_PTR ptr, const u8 inNetID, const u16 inX, const u16 inY);
static BOOL CheckPokeCircle(SHOT_POKE * poke1, SHOT_POKE * poke2);
static BOOL CheckCircle(const VecFx32 *inVec1, const fx32 inRange1,
		const VecFx32 *inVec2, const fx32 inRange2);
static void ResetBall(SHOT_BALL *ball);
static void ChgBallDir(PKTHLN_SHOT_PTR ptr, SHOT_BALL *ball, const VecFx32 *inDirVec);
static void HitBall(PKTHLN_PTR work);
static void MoveBall(PKTHLN_PTR work);
static void SwitchBallInfo( SHOT_BALL *ball1, SHOT_BALL *ball2 );
static void SwitchBallInfoCore( SHOT_BALL *my_ball, const SHOT_BALL *target_ball, const u8 inIdx);
static void CheckGoal(PKTHLN_PTR work);
static void SetFatigue(PKTHLN_PTR work);

static void CalcVec(const VecFx32 *inVec1, const VecFx32 *inVec2, VecFx32 *outVec);
static fx32 GetCos( const VecFx32 *inVec1, const VecFx32 *inVec2 );
static fx32 GetSin( const VecFx32 *inVec1, const VecFx32 *inVec2 );
static BOOL CheckRotIO( const VecFx32 *inVec1, const VecFx32 *inVec2, const u16 inRad );
///static void CheckScore(PKTHLN_SHOT_PTR ptr);
static void RecoverStamina(SHOT_POKE *outPoke);
static void SetPokeParam(PKTHLN_PTR work, const SHOT_PARAM *inData, const u8 inNetID, const u8 inIdx, SHOT_POKE *outPoke);



static void SetRecordStr(PKTHLN_SHOT_PTR ptr, const int inPoint);

static HIT_CHECK WallHitCheck(	const VecFx32 *inNewPoint, const VecFx32 *inOldPoint, const int inRange,
								const BOOL inGlLineCheck, VecFx32 *outVec	);
static BOOL CheckCrossAfter(Vec2DS32 *w_srt, Vec2DS32 *w_end,
		Vec2DS32 *t_srt, VecFx32 *end);
static VecFx32 FixBallDir(PKTHLN_SHOT_PTR ptr, const VecFx32 *inDirVec );

static BOOL CheckCorssWall(const VecFx32 *inWsVec, const VecFx32 *inWeVec,
		const VecFx32 *inTsVec, const VecFx32 *inTeVec, VecFx32 *outCross);
static void GenerateBall(PKTHLN_SHOT_PTR ptr, SHOT_BALL *ball);

static u8 GetCommBallY(SHOT_BALL *ball);
static fx32 GetBallDispY(int inY);
static void UpdateDamageSpin(SHOT_POKE* shot_poke);
static void PlayBallAppSE(PKTHLN_SHOT_PTR ptr, const u8 inBallIdx, const u8 inIsGold, const int inY);

static void WriteNameStr(PKTHLN_SHOT_PTR ptr, const u8 inNetID, const GOAL_TYPE inGoal);
static void MakePlayerGoalStr(PKTHLN_PTR work);
static void DelPlayerGoalStr(PKTHLN_PTR work);

static const u8 GetGoalIdx(const SHOT_BALL * inBall);
static const u8 GetGoalIdxByXY(const int inX, const int inY);

static const void SetTopFlg(PKTHLN_SHOT_PTR ptr);
static void PrintPlayerName(PKTHLN_SHOT_PTR ptr);

static void SortPpkePriority(SHOT_POKE *my_poke, u8 *inMyPokeY);
static s32 CompFunc(void *elem1, void *elem2);
static void SortEnemyPoke(PKTHLN_SHOT_PTR ptr, SHOT_PARENT_DATA *parent, const u8 inMyNetID);

static void RecCallBack(PKTHLN_PTR work);

//ゴール演出TCB関連
static void SetupGoalEffTcb(PKTHLN_SHOT_PTR ptr);
static void DelGoalEffTcb(PKTHLN_SHOT_PTR ptr);
static void ReqGoalEff(PKTHLN_SHOT_PTR ptr, const u8 inIdx, const u8 inIsPlus, const u8 inIsGold);
static void GoalEffTcb(TCB_PTR tcb, void* work);
static const u8 CalcGallEffBallY(const u8 inGoalIdx, const u8 inOwnerPlayer);

PKTHLN_FUNC ShotFuncTbl[] = {
	SHOT_Func_Phase1,
	SHOT_Func_Phase2,
};

enum {
	SHOT_SEQ_PHASE1,
	SHOT_SEQ_PHASE2,
};

typedef struct POSDATA_tag
{
	s16 X;
	s16 Y;
}POSDATA;

typedef struct MY_POKE_SORT_tag
{
	u8 *PosY;
	SHOT_POKE *Poke;
}MY_POKE_SORT;

//初期配置テーブル
static const POS_DATA InitPos[ENTRY_MEMBER_NUM_MAX][ENTRY_MAX] = {
	{ { 11*8, 10*8},{ 6*8,  10*8},{ 9*8,  7*8} },
	{ { 21*8, 10*8},{ 26*8, 10*8},{ 23*8, 7*8} },
	{ { 11*8, 16*8},{ 6*8,  16*8},{ 9*8,  19*8} },
	{ { 21*8, 16*8},{ 26*8, 16*8},{ 23*8, 19*8} },
};

//アタックスピードテーブル
static const u8 AttackSpeed[5] = {
	7,7,6,5,4
};

#include "system/arc_tool.h"

const VecFx32 gpost_vec[ENTRY_MEMBER_NUM_MAX][GPOST_NUM] = {
	{
		{GPOST2_X,GPOST1_Y,0}, {GPOST1_X,GPOST2_Y,0},
	},
	{
		{GPOST3_X,GPOST1_Y,0}, {GPOST4_X,GPOST2_Y,0},
	},
	{
		{GPOST2_X,GPOST4_Y,0}, {GPOST1_X,GPOST3_Y,0},
	},
	{
		{GPOST3_X,GPOST4_Y,0}, {GPOST4_X,GPOST3_Y,0},
	},
};

const Vec2DS32 GoalVec[ENTRY_MEMBER_NUM_MAX][GPOST_NUM] = {
	{
		{G2_X, G1_Y}, {G1_X, G2_Y},
	},
	{
		{G4_X, G2_Y}, {G3_X, G1_Y},
	},
	{
		{G1_X, G3_Y}, {G2_X, G4_Y},
	},
	{
		{G3_X, G4_Y}, {G4_X, G3_Y},
	},
};

static const POSDATA BallGenePos[BALL_GENE_POS_NUM] = {
	{10*8,11*8},{13*8,11*8},{16*8,11*8},{19*8,11*8},{22*8,11*8},
	{10*8,13*8},{13*8,13*8},{16*8,13*8},{19*8,13*8},{22*8,13*8},
	{10*8,15*8},{13*8,15*8},{16*8,15*8},{19*8,15*8},{22*8,15*8},
};

static u8 BallAppOfs[BALL_APP_COUNT] = {
	0,4,2,1,0,1,0,1,
};

static const VecFx32 MyGoalEffPos[ENTRY_MEMBER_NUM_MAX] = {
	{0*FX32_ONE, 40*FX32_ONE, 0},
	{255*FX32_ONE, 40*FX32_ONE, 0},
	{0*FX32_ONE, 152*FX32_ONE, 0},
	{255*FX32_ONE, 152*FX32_ONE, 0},
};

#include "pkthln_shot.dat"

//--------------------------------------------------------------------------------------------
/**
 * 初期化関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
PTH_RC PE_SHOT_InitFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);
	u8 seq = PTFrame_GetSubSeq(work);
	switch(seq){
	case 0:
		{
			int heap_id;
			sys_CreateHeap( HEAPID_POKETHLON, HEAPID_PT_SHOT, SHOT_HEAP_SIZE );
			heap_id = HEAPID_PT_SHOT;

			sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
			sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

			GF_Disp_GX_VisibleControlInit();
			GF_Disp_GXS_VisibleControlInit();
			GX_SetVisiblePlane( 0 );
			GXS_SetVisiblePlane( 0 );

			//VRAMバンク割り当て
			SetVramBank();
			//アプリケーションメモリー
			ptr = PTFrame_AllocEventWork(work, sizeof(PKTHLN_SHOT));
			MI_CpuClear8( ptr, sizeof(PKTHLN_SHOT));
			//ソートバッファアロック
			{
				ptr->PokeSortBuf = sys_AllocMemory(heap_id, POKE_SORT_BUF_SIZE);
				MI_CpuClear8( ptr->PokeSortBuf, POKE_SORT_BUF_SIZE);
			}

			//BGLアロケーション
			ptr->bgl = GF_BGL_BglIniAlloc(heap_id);

			//レコード表示ＢＧのセット
			PTFrame_SetRecBGMask(work, GX_PLANEMASK_BG3);

			{
				CHAR_MANAGER_MAKE cm;
				cm.CharDataNum = SHOT_EVENT_OBJ_NUM;
				cm.VramTransAreaMain = 256*1024;
				cm.VramTransAreaSub = 16*1024;
				cm.heap = heap_id;

				//キャラ・パレットマネージャ初期化
				PKTHLN_OBJ_COMMON_InitCharPlttManager(	&cm,
														SHOT_EVENT_PAL_NUM,
														heap_id,
														GX_OBJVRAMMODE_CHAR_1D_256K,
														GX_OBJVRAMMODE_CHAR_1D_32K);
			}

			// OAMマネージャーの初期化
			NNS_G2dInitOamManagerModule();

			// 共有OAMマネージャ作成
			// レンダラ用OAMマネージャ作成
			// ここで作成したOAMマネージャをみんなで共有する
			REND_OAMInit(
					0, 126,		// メイン画面OAM管理領域
					0, 32,		// メイン画面アフィン管理領域
					1, 126,		// サブ画面OAM管理領域	<<サブ画面に通信アイコンを表示するためOAM開始を1にする（0は通信アイコンが使用）
					0, 32,		// サブ画面アフィン管理領域
					heap_id);
			ptr->HeapID = heap_id;
		}

		//タッチフォントロード
		FontProc_LoadFont(FONT_TOUCH, ptr->HeapID);

		BgInit(ptr->bgl);

		//BMP
		CreateBmpWin(ptr);

		//文字列作成
		MakePlayerGoalStr(work);

		//プレーヤー名表示
		{
			u8 i;
			for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
				WriteNameStr(ptr, i, GOAL_NONE);
			}
		}
		//ゴール演出TCB作成
		SetupGoalEffTcb(ptr);

		//下画面をメインにする
		sys.disp3DSW = DISP_3D_TO_SUB;
		GF_Disp_DispSelect();

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 1:
		ptr->SubDispCntPtr = ShotSub_Init( ptr->HeapID, ptr->bgl, work);
		ptr->AICntPtr = ShotAI_Init(ptr->HeapID,
				ENTRY_MEMBER_NUM_MAX-PTFrame_GetPlayerNum(work), PTFrame_GetGameType(work));
		ptr->CmnResCntPtr =
			CmnRes_Init( ptr->HeapID,
						 CMN_RES_ALL_BIT|CMN_RES_F2X2SUB_BIT|CMN_RES_PEN_M_BIT|CMN_RES_CUR_BIT,
						 NNS_G2D_VRAM_TYPE_2DMAIN );

		//▼マーカ初期化
		PTFrame_InitPosMarker(work);

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 2:
		{
			int i, j;
			PKTHLN_ACT_SETUP_PRM param = {
				ACT_MAX,2,{2,2,2,2}
			};
			ptr->ActCntPtr = PkthlnClAct_Init(ptr->HeapID, &param);

			//上下画面幅設定
			PkthlnClAct_SetDispDistance(ptr->ActCntPtr,
										0, 0,
										0, SUB_DISP_DISTANCE );
			//ポケモンアクター
			ptr->PokeActCntPtr = PokeAct_Init( ptr->HeapID, SHOT_EVENT_POKE_NUM, PRI_POKE_MINE,
									  ptr->CmnResCntPtr, PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr) );

			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 0, RES_CODE_SHOT_MAIN);
			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 1, RES_CODE_SHOT_SUB);
			//
			PkthlnClAct_SetChar( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_main_NCGR,
							RES_CODE_SHOT_MAIN, NNS_G2D_VRAM_TYPE_2DMAIN);
			PkthlnClAct_SetPaltt( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_main_NCLR,
							RES_CODE_SHOT_MAIN, NNS_G2D_VRAM_TYPE_2DMAIN, SHOT_MAIN_PALETTE_NUM	);
			PkthlnClAct_SetCell( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_main_NCER, RES_CODE_SHOT_MAIN );
			PkthlnClAct_SetAnm(	ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_main_NANR, RES_CODE_SHOT_MAIN );

			PkthlnClAct_SetChar( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_sub_NCGR,
							RES_CODE_SHOT_SUB, NNS_G2D_VRAM_TYPE_2DSUB);
			PkthlnClAct_SetPaltt( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_sub_NCLR,
							RES_CODE_SHOT_SUB, NNS_G2D_VRAM_TYPE_2DSUB, SHOT_SUB_PALETTE_NUM	);
			PkthlnClAct_SetCell( ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_sub_NCER, RES_CODE_SHOT_SUB	);
			PkthlnClAct_SetAnm(	ptr->ActCntPtr,
							ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_obj_sub_NANR, RES_CODE_SHOT_SUB	);

			//トランス
			PkthlnClAct_Trans(ptr->ActCntPtr);


			for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
				//汗orヒヨコ
				ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX].StateActPtr =
					PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_STATE);
				//プライオリティ
				PkthlnClAct_SetPriority(ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX].StateActPtr, PRI_STATE);
				//ダッシュエフェクト
				for (j=0;j<DASH_EFF_NUM;j++){
					ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX].DashActPtr[j] =
						PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_DASH);
					//プライオリティ
					PkthlnClAct_SetPriority(ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX].DashActPtr[j], PRI_DASH_EFF);
				}
			}
			//ボール
			for(i=0;i<BALL_MAX;i++){
				SHOT_BALL *ball;
				VecFx32 vec = {0,0,0};
				ball = &ptr->Ball[i];

				ball->BallActPtr =
					PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_BALL);
				ball->EffActPtr =
					PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_BLEFF);
				PkthlnClAct_ChgAnm(ball->BallActPtr, 10);
				PkthlnClAct_ChgAnm(ball->EffActPtr, 13);
				//プライオリティ
				PkthlnClAct_SetPriority(ball->BallActPtr, PRI_BALL);
				//プライオリティ
				PkthlnClAct_SetPriority(ball->EffActPtr, PRI_BALL_EFF);

				ResetBall(ball);
				ball->State = BALL_STATE_NORMAL;
				vec.x = BallGenePos[START_BALL_GENE_POS_IDX].X * FX32_ONE;
				vec.y = BallGenePos[START_BALL_GENE_POS_IDX].Y * FX32_ONE;
				//座標セット
				PkthlnClAct_SetPos(ball->BallActPtr, &vec);
				PkthlnClAct_SetPos(ball->EffActPtr, &vec);
				ball->Pos = vec;
				ball->GeneIdx = START_BALL_GENE_POS_IDX;
				if (i==0){
					PkthlnClAct_SetActive(ball->BallActPtr, TRUE, TRUE);
					ball->Type = BALL_TYPE_NORMAL;
				}
			}
			//ゴール
			{
				u16 rot[ENTRY_MEMBER_NUM_MAX] = { 0,0x4000,0xc000,0x8000, };
				VecFx32 goal_vec[ENTRY_MEMBER_NUM_MAX] = {
					{GOAL1_X,GOAL1_Y,0},
					{GOAL2_X,GOAL2_Y,0},
					{GOAL3_X,GOAL3_Y,0},
					{GOAL4_X,GOAL4_Y,0},
				};

				for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
					ptr->GoalActPtr[i] =
						PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_GOAL);
					PkthlnClAct_SetActive(ptr->GoalActPtr[i], TRUE, TRUE);
					PkthlnClAct_ChgAnm(ptr->GoalActPtr[i], 1);
					//座標セット
					PkthlnClAct_SetPos(ptr->GoalActPtr[i], &goal_vec[i]);
					//回転
					PkthlnClAct_SetRotationAffine(ptr->GoalActPtr[i], rot[i], CLACT_AFFINE_NORMAL );
					//プライオリティ
					PkthlnClAct_SetPriority(ptr->GoalActPtr[i], PRI_GOAL);
					//ゴールポスト
					for(j=0;j<GPOST_NUM;j++){
						PKTHLN_ACT_PTR act_ptr;
						act_ptr = PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_POST);
						PkthlnClAct_SetActive(act_ptr, TRUE, TRUE);
						PkthlnClAct_ChgAnm(act_ptr, 2+(i*2)+j);
						//座標セット
						PkthlnClAct_SetPos(act_ptr, &gpost_vec[i][j]);
						//プライオリティ
						PkthlnClAct_SetPriority(act_ptr, PRI_POST);
					}

					//自分ゴールエフェクト
					ptr->MyGoalActPtr[i] =
						PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN,
								RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_MY_GOAL);
					//座標セット
					PkthlnClAct_SetPos(ptr->MyGoalActPtr[i], &MyGoalEffPos[i]);
					//プライオリティ
					PkthlnClAct_SetPriority(ptr->MyGoalActPtr[i], PRI_MY_GOAL);

					//ポストフラッシュ
					ptr->PostFlashActPtr[i] =
						PkthlnClAct_SetGetActor(ptr->ActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_SHOT_MAIN, ACT_CODE_SHOT_POST_FLASH);
					//座標セット
					PkthlnClAct_SetPos(ptr->PostFlashActPtr[i], &goal_vec[i]);
					//プライオリティ
					PkthlnClAct_SetPriority(ptr->PostFlashActPtr[i], PRI_POST_FLASH);

				}
			}

			//カウントダウンアクター
			{
				CLACT_WORK_PTR	*act_adr;
				act_adr = PTFrame_SetCountDown( work, 0, ptr->CmnResCntPtr, ptr->ActCntPtr );
				//プライオリティセット
				CLACT_DrawPriorityChg( *act_adr, PRI_COUNT );
			}
			//サブ画面ポケ以外のＯＢＪ
			ShotSub_SetObj(ptr->ActCntPtr, ptr->SubDispCntPtr, ptr->CmnResCntPtr);

		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 3:
		{
			int i;
			MONS_INFO info[SHOT_EVENT_POKE_NUM];
			PCLACT_SET_PARAM param;

			for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
				PTFrame_SetMonsInfo(work, i/ENTRY_MAX, i%ENTRY_MAX, &info[i]);

				param.ShadowPos[i] =
					PTFrame_GetPokeShdwPosType(PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX));
			}
			param.Quick = 0;
			param.BGPriority = 1;
			param.Trans = 0;
			param.ResVramType = NNS_G2D_VRAM_TYPE_2DMAIN;
			param.DrawArea = NNS_G2D_VRAM_TYPE_2DMAIN;

			PokeAct_SetPokeActor(	ptr->PokeActCntPtr, SHOT_EVENT_POKE_NUM,
									info, &param,
									PCLACT_TCB_PRIORITY,
									0 );

		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 4:
		if ( PokeAct_CheckActSetTask(ptr->PokeActCntPtr) ){
			PEN_POS pen_pos[ENTRY_MAX];

			EVT_HIT_DATA hit_data;
			int i;
			int my_net_id;

			my_net_id = PTFrameGetCurrentID(work);

			PTFrame_SetDefaultVBlankFunc(ptr->bgl);	// VBlankセット
			//描画を許可
			PTFrame_SetDraw(work, TRUE);

			ArchiveDataLoad(hit_data.Data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_push_hit_bin);

			//ポケセルアクター可視化
			for (i=0;i<SHOT_EVENT_POKE_NUM;i++){
				POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
				PokeAct_DispCnt(poke_ptr, 1);	//表示

				//あたり判定データセット
				{
					HIT_TYPE hit_type;
					hit_type = PTFrame_GetPokeHitType(PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX));
					PokeAct_SetHitData(poke_ptr, hit_data.Data[hit_type-1].Ofs, hit_data.Data[hit_type-1].Range);
///					OS_Printf("hitdata::%d,%d\n",hit_data.Data[hit_type-1].Ofs,hit_data.Data[hit_type-1].Range);
				}

				//ポケモン初期位置
				{
///					const MONS_INFO *info;
					SHOT_POKE *shot_poke;
					int space;
					POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
					PCLACT_PTR	pclact_ptr = PokeAct_GetPclActPtr(poke_ptr);
///					VecFx32 aff_vec = {0,0,0};

					shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
					shot_poke->PokeActPtr = poke_ptr;
					shot_poke->HitRange = PokeAct_GetHitRange(poke_ptr);
					shot_poke->State = SP_STATE_NORMAL;

					space = PCLACT_GetSpaceHeight(pclact_ptr);
#if 0
					info = PCLACT_GetMonsInfo(pclact_ptr);
					if (info->CellType){
						aff_vec.x = (POKE_L_SIZE/2)*FX32_ONE;
						aff_vec.y = (space+(POKE_L_SIZE-space)/2)*FX32_ONE;
					}else{
						aff_vec.x = (POKE_S_SIZE/2)*FX32_ONE;
						aff_vec.y = (space+(POKE_S_SIZE-space)/2)*FX32_ONE;
					}
#endif
					//テーブルで位置決定
					{
						int sx,sy, tx,ty;
						int range;
						//影の位置
						sx = InitPos[i/ENTRY_MAX][i%ENTRY_MAX].X;
						sy = InitPos[i/ENTRY_MAX][i%ENTRY_MAX].Y;

						shot_poke->Dir = POKE_DIR_DOWN;
						//向きセット
						PokeAct_SetDir(poke_ptr, POKE_DIR_DOWN);
						//アクター位置セット
////						PokeAct_SetPos(poke_ptr, x+ofs_x, y+ofs_y, TRUE);
						PokeAct_SetPosShadow(poke_ptr, sx, sy);
						//タッチ半径セット
						range =
							PTFrame_GetPokeTouchRange();
						PokeAct_SetTouchRange(poke_ptr, range);
///						shot_poke->Range = range*FX32_ONE;

						//タッチ中心座標取得
						PokeAct_GetTouchPosByShadowPos(poke_ptr, sx, sy, &tx, &ty);

						shot_poke->Pos.x = tx*FX32_ONE;
						shot_poke->Pos.y = ty*FX32_ONE;
						shot_poke->NowPoint.x = tx*FX32_ONE;
						shot_poke->NowPoint.y = ty*FX32_ONE;
						shot_poke->LastPoint.x = tx*FX32_ONE;
						shot_poke->LastPoint.y = ty*FX32_ONE;

						//ポケモンプライオリティ(自分のポケは表示優先度が高い)
						if (i/ENTRY_MAX == PTFrameGetCurrentID(work)){
							PokeAct_SetPriority(poke_ptr, PRI_POKE_MINE);
						}else{
							PokeAct_SetPriority(poke_ptr, PRI_POKE);
						}
						//ポケモン、影、マーカーのプライオリティ間隔の設定
						PokeAct_ChgPriorityOfs(poke_ptr, PRI_MARGINE);
#if 0
						//アフィンセット
						PokeAct_SetAffine(poke_ptr, CLACT_AFFINE_NONE);
						//アフィン座標セット
						PokeAct_SetAffineVec(poke_ptr, &aff_vec);
#endif
						//自分のポケ3体のペン表示座標を保存
						if ( (i/ENTRY_MAX)==my_net_id ){
							pen_pos[i%ENTRY_MAX].X = tx;
							pen_pos[i%ENTRY_MAX].Y = ty;

							//▼マーカーセット
							PTFrame_SetPosMarker( work, poke_ptr, ptr->CmnResCntPtr,
									    		  PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr), 1);
						}

					}//テーブルで位置決定
				} //ポケモン初期位置
			}	//end for

			//ペン表示
			PTFrame_SetPen( work, 0, ptr->CmnResCntPtr, ptr->ActCntPtr,
						    NNS_G2D_VRAM_TYPE_2DMAIN, ENTRY_MAX,  pen_pos);

			if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){
				SHOT_PARAM data;
				int i;
				SHOT_POKE *shot_poke;
				ArchiveDataLoad(&data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_shot_bin);

				for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
					int j;
					//親の判定データ初期化
					ptr->HoldPokeNo[i] = SHOT_EVENT_POKE_NUM;
					//パラメータ格納
					for(j=0;j<ENTRY_MAX;j++){
						shot_poke = &ptr->Poke[i][j];
						SetPokeParam(work, &data, i, j, shot_poke);
						ShotAI_SetupPoke( ptr->AICntPtr, i*ENTRY_MAX+j, shot_poke );
					}
				}

				ShotAI_SetupBall( ptr->AICntPtr, ptr->Ball );
				ShotAI_SetPokePosition( ptr->AICntPtr );

				//ボールの基本方向ベクトルの作成
				{
					VecFx32 base_x = {FX32_ONE,0,0};
					VecFx32 base_y = {0,FX32_ONE,0};
					VecFx32 base_xy = {FX32_ONE,FX32_ONE,0};
					VEC_Normalize(&base_xy, &base_xy);
					ptr->BallBaseDir[0] = base_x;
					ptr->BallBaseDir[1] = base_x;
					ptr->BallBaseDir[1].x *= (-1);
					ptr->BallBaseDir[2] = base_y;
					ptr->BallBaseDir[3] = base_y;
					ptr->BallBaseDir[3].y *= (-1);

					ptr->BallBaseDir[4] = base_xy;
					ptr->BallBaseDir[5] = base_xy;
					ptr->BallBaseDir[5].x *= (-1);
					ptr->BallBaseDir[6] = base_xy;
					ptr->BallBaseDir[6].y *= (-1);
					ptr->BallBaseDir[7] = base_xy;
					ptr->BallBaseDir[7].x *= (-1);
					ptr->BallBaseDir[7].y *= (-1);
				}
			}

			//親のとき、初回送信データを作成
			if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){
				COMM_EVENT_COMMON_DATA *data;
				SHOT_PARENT_DATA *parent;
				data = PTFrame_GetEvtComCmnData(work);
				parent = PKTHLN_CommPack_GetData(&data->SendShareData);
				SetCommInfo(ptr, parent);
			}

			SetGraphic(ptr);
			ShotSub_WriteWinInfo(ptr->SubDispCntPtr);

			//ＯＢＪの表示
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// MAIN DISP OBJ ON
			GF_Disp_GXS_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// SUB DISP OBJ ON

			//ゲーム時間セット
			ptr->Timer = GAME_TIME;
			//タイマー表示
			ShotSub_DispTime(ptr->SubDispCntPtr, ptr->Timer);
			//通信アイコン(サブ画面)
			WirelessIconEasyPokethlon( NNS_G2D_VRAM_TYPE_2DSUB );

			//フェードイン
			WIPE_SYS_Start(	WIPE_PATTERN_FSAM, WIPE_TYPE_SHUTTERIN_DOWN,
					WIPE_TYPE_SHUTTERIN_DOWN, WIPE_FADE_BLACK,
					WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
			//次のシーケンスへ
			PTFrame_IncSubSeq(work);

		}
		break;
	case 5:
		//フェードイン待ち
		if( WIPE_SYS_EndCheck() ){
			//初期化終了
			sys_PrintHeapFreeSize( ptr->HeapID );
			return PTH_RC_END;
		}
		break;
	}
	return PTH_RC_LOOP;
}

//--------------------------------------------------------------------------------------------
/**
 * 描画関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_SHOT_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	PkthlnClAct_Draw(ptr->ActCntPtr);
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * 競技結果計算関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_SHOT_ResultFunc(PKTHLN_PTR work, void *pParam)
{
	int i,j;
	RSLT_PTR result_ptr;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	OS_Printf("競技結果データ作成\n");

	result_ptr = PTFrame_GetResultPtr(work);
	RSLT_Setup( result_ptr );

	for( i=0;i<ENTRY_MEMBER_NUM_MAX;i++ ){
		int rec;
		rec = PTFrame_GetEvtResult(work, i);
		RSLT_SetResult(	work, result_ptr,
							i, rec,
							0, 3, msg_pkthln_new_record10 );
	}

	//ソート
	RSLT_Sort(result_ptr, SORT_REC_LARGE);
	//得点セット
	PTC_CalcPoint(result_ptr, PKTHLN_EVT_SHOT);

	//総得点に加算
	RSLT_AddTotalScore(result_ptr);

	//競技得点セット
	RSLT_SetEvtScore(result_ptr, PKTHLN_EVT_SHOT);

	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * 終了関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_SHOT_EndFunc(PKTHLN_PTR work, void *pParam)
{
	int i;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	// 通信アイコン撤去
	WirelessIconEasyEnd();

	//▼マーカ終了
	PTFrame_EndPosMarker(work);

	//BG削除
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME3_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_S );

	//ゴール演出TCB削除
	DelGoalEffTcb(ptr);

	//文字列削除
	 DelPlayerGoalStr(work);

	//BMP
	GF_BGL_BmpWinDel( &ptr->Win );
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		GF_BGL_BmpWinDel( &ptr->NameWin[i] );
	}

	//BGL解放
	sys_FreeMemoryEz(ptr->bgl);

	//アクター解放
	PkthlnClAct_Free(ptr->ActCntPtr);

	//ポケアクターコントローラ解放
	PokeAct_Free(ptr->PokeActCntPtr);
	//共通リソースコントローラ解放
	CmnRes_Free(ptr->CmnResCntPtr);

	//OAMレンダラー破棄
	REND_OAM_Delete();

	DeleteCharManager();
	DeletePlttManager();

	//AIコントローラー解放
	ShotAI_End(ptr->AICntPtr);
	//サブ画面コントローラー解放
	ShotSub_Free(ptr->SubDispCntPtr);

	//タッチフォントアンロード
	FontProc_UnloadFont(FONT_TOUCH);

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	//ソートバッファ解放
	sys_FreeMemoryEz(ptr->PokeSortBuf);

	//イベントワーク解放
	PTFrame_FreeEventWork(work);

	// 上下画面を元に戻しておく
	sys.disp3DSW = DISP_3D_TO_MAIN;
	GF_Disp_DispSelect();

	//特殊効果オフ
	G2_BlendNone();

	//ヒープ解放
	sys_DeleteHeap( HEAPID_PT_SHOT );

	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * VRAM設定		ポケスロンでは、ポケモン表示だけで0x30000必要となる。
 * VRAM_AB(0x40000)でないとはいらん
 *
 * @param	none
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM tbl = {
		GX_VRAM_BG_64_E,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット

		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット

		GX_VRAM_OBJ_256_AB,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット

		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット

		GX_VRAM_TEX_NONE,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_NONE			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &tbl );
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL SHOT_Func_Phase1(PKTHLN_PTR work, u8 *seq)
{
	BOOL rc;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch(*seq){
	case 0:	//カウント
		if ( PTFrame_CountDown(work) ){
			(*seq)++;
		}
		break;
	case 1:
		CommMain(work);
		if ( ControlMain(work) ){
			(*seq)++;
		}
		break;
	case 2:
		CommMain(work);
		//4シンクに1度しか自分の得点が送信されないので、競技が終わっても上画面のスコアデータだけは取り続ける
		UpdataSubDispScore(work);
		if ( PTFrame_DispEnd(work) ){
			//フェードアウトリクエスト
			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
							WIPE_TYPE_FADEOUT, WIPE_FADE_BLACK,
							WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, SHOT_SEQ_PHASE2);
		}
	}


	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL SHOT_Func_Phase2(PKTHLN_PTR work, u8 *seq)
{
	int point;
	int i,j;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	if (*seq == 0){
		//フェードアウト待ち
		if ( WIPE_SYS_EndCheck() ){
			*seq = 1;
		}
		return FALSE;
	}

	//結果はすべて親が管理しているので、子は処理をスルー
	if (PTFrameGetCurrentID(work) != COMM_PARENT_ID){
		return TRUE;
	}

	//結果セット
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		point = ptr->TotalScore[i];
		PTFrame_SetEvtResultOrg(work, i, point);
	}
	return TRUE;
}
//----------------------------------------------------------------------------
/**
 *	@brief	RECT_HIT_TBLを登録
 *
 *	@param	*rect		矩形データポインタ
 *	@param	x			X
 *	@param	y			Y
 *	@param	sizx		X幅
 *	@param	sizy		Y幅
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SetPokeRectHitTable(RECT_HIT_TBL *rect, int x, int y, int sizx, int sizy)
{
  rect->rect.top    = y - sizy / 2;
  rect->rect.left   = x - sizx / 2;
  rect->rect.bottom = y + sizy / 2;
  rect->rect.right  = x + sizx / 2;
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	BG初期化
 * @param	*ini		BGL
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void BgInit(GF_BGL_INI * ini)
{
	{	/* BG SYSTEM */
  	  GF_BGL_SYS_HEADER BGsys_data = {
    	  GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BGMODE_1, GX_BG0_AS_2D,
    	};
  	  GF_BGL_InitBG( &BGsys_data );
  	}

  	//メイン
  	{	/* MAIN DISP BG0 */
    	GF_BGL_BGCNT_HEADER MBg0_Data = {
	      0, 0, 0x800, 0,
    	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xe800, GX_BG_CHARBASE_0x00000,
		  GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_M, &MBg0_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME0_M );
 	}

	{	/* MAIN DISP BG1 */
  	  GF_BGL_BGCNT_HEADER MBg1_Data = {
    	  0, 0, 0x800, 0,
   	 	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x04000,
    	  GX_BG_EXTPLTT_01, 2, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_M, &MBg1_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME1_M );
	}
	{	/* MAIN DISP BG2 */
  	  GF_BGL_BGCNT_HEADER MBg2_Data = {
    	  0, 0, 0x800, 0,
   	 	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xd800, GX_BG_CHARBASE_0x08000,
    	  GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_M, &MBg2_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME2_M );
	}

	{	/* MAIN DISP BG3 */
    	GF_BGL_BGCNT_HEADER MBg3_Data = {
	      0, 0, 0x800, 0,
    	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xd000, GX_BG_CHARBASE_0x0c000,
		  GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME3_M, &MBg3_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME3_M );
 	}

	  //サブ
	{	/* SUB DISP BG0 */
 	   GF_BGL_BGCNT_HEADER SBg0_Data = {
    	  	0, 0, 0x800, 0,
   	  		GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
			GX_BG_SCRBASE_0xf800, GX_BG_CHARBASE_0x00000,
    		GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
  	  };
 	  GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_S, &SBg0_Data, GF_BGL_MODE_TEXT );
  	  GF_BGL_ScrClear( ini, GF_BGL_FRAME0_S );
 	}

 	{	/* SUB DISP BG1 */
	    GF_BGL_BGCNT_HEADER SBg1_Data = {
    	  	0, 0, 0x800, 0,
 	  		GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
 	   		GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x04000,
  	   		GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
		};
    	GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_S, &SBg1_Data, GF_BGL_MODE_TEXT );
    	GF_BGL_ScrClear( ini, GF_BGL_FRAME1_S );
	}

	{	/* SUB DISP BG2 */
	    GF_BGL_BGCNT_HEADER SBg2_Data = {
    	  	0, 0, 0x800, 0,
 	  		GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
 	   		GX_BG_SCRBASE_0xe800, GX_BG_CHARBASE_0x08000,
  	   		GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
		};
    	GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_S, &SBg2_Data, GF_BGL_MODE_TEXT );
    	GF_BGL_ScrClear( ini, GF_BGL_FRAME2_S );
	}

	//レコードＢＧ非表示
	GF_Disp_GX_VisibleControl( GX_PLANEMASK_BG3, VISIBLE_OFF );
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	グラフィックセット
 * @param	ptr			アプリポインタ
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetGraphic(PKTHLN_SHOT_PTR ptr)
{
	//メインキャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_main01_ncgr,
						ptr->bgl, GF_BGL_FRAME1_M, 0, 0, FALSE, ptr->HeapID);
	ArcUtil_BgCharSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_main03_ncgr,
						ptr->bgl, GF_BGL_FRAME2_M, 0, 0, FALSE, ptr->HeapID);

	//サブキャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_sub01_ncgr,
						ptr->bgl, GF_BGL_FRAME1_S, 0, 0, FALSE, ptr->HeapID);
	ArcUtil_BgCharSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_sub03_ncgr,
						ptr->bgl, GF_BGL_FRAME2_S, 0, 0, FALSE, ptr->HeapID);

	//メインスクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_main01_nscr,
						ptr->bgl, GF_BGL_FRAME1_M, 0, 0, FALSE, ptr->HeapID);
	//メインスクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_main03_nscr,
						ptr->bgl, GF_BGL_FRAME2_M, 0, 0, FALSE, ptr->HeapID);

	//サブスクリーン
	ShotSub_SetScreen(ptr->SubDispCntPtr);

	//メインパレット
	ArcUtil_PalSet( ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_main_nclr,
						PALTYPE_MAIN_BG, 0, 32*4, ptr->HeapID );
	//サブパレット
	ArcUtil_PalSet( ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_bg_sub_nclr,
						PALTYPE_SUB_BG, 0, 32*2, ptr->HeapID );
}

//----------------------------------------------------------------------------
/**
 *	@brief		メイン関数
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return	終了でTRUE
 */
//-----------------------------------------------------------------------------
static BOOL ControlMain(PKTHLN_PTR work)
{
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	SHOT_CHILD_DATA *child_data;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	child_data = PKTHLN_CommPack_GetData(&data->SendData);
	child_data->TouchValid = FALSE;

	//終了検出
	{
		u8 end;
		SHOT_PARENT_DATA *parent;
		parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
		end = (parent->St2 >> (SHOT_EVENT_POKE_NUM*2)) & 0x1 ;	//1ビットマスク

#ifdef PM_DEBUG
		if (sys.trg & PAD_BUTTON_X){
			end = 1;
		}
#endif
		if (end){
			//アクター停止
			PkthlnClAct_AllAnmStop(ptr->ActCntPtr, 1);
			PokeAct_AllAnmStop(ptr->PokeActCntPtr, 1);
			PTFrame_StopPosMarker(work);

			//レコードコールバック関数をセット
			PTFrame_SetRecordCallBack(work, RecCallBack);
#if 0
			//ニューレコード用にレコードをセット
			{
				u8 point;
				point = ShotSub_GetDispScore(ptr->SubDispCntPtr);
				//フレームワークにニューレコードチェック用のレコード値をセット
				PTFrame_SetCheckRecord(work, point);
				SetRecordStr(ptr, point);
			}
#endif
			return TRUE;
		}
	}

	//タッチ座標検出
	if (GF_TP_GetTrg()){
		//アクションポイント加算「タッチ回数」
		PTFrame_AddActionPoint(	work, PTFrameGetCurrentID(work), ENTRY_MAX, ADD_TYPE_TOUCH, 1 );
	}
	if (GF_TP_GetCont()){
		//通信データに座標をセット
		child_data->TpX = sys.tp_x;
		child_data->TpY = sys.tp_y;
		child_data->TouchValid = TRUE;
	}

	SetDraw(work);

	return FALSE;
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	通信データ関連メイン処理
 * @param	work		ポケスロンアプリポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CommMain(PKTHLN_PTR work)
{
	int i;
	PKTHLN_SHOT_PTR ptr;
	SHOT_CHILD_DATA *child_data;
	SHOT_PARENT_DATA *parent;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	ptr = PTFrame_GetEventWorkPtr(work);

	//※この競技は各機が時間更新を行う

	//時間経過
#ifdef PM_DEBUG					//こっちデバッグ用
	if (!DebugPkthlnWk.TimeInfinity){
		if (ptr->Timer > 0){
			ptr->Timer--;
		}
	}
#else							//こっち製品用
	if (ptr->Timer > 0){
		ptr->Timer--;
	}
#endif

	//親動作
	if ( PTFrameGetCurrentID(work) == COMM_PARENT_ID ){

		//終了フラグが立っているならば、通信データのセットのみを行い処理を打ち切る
		if (ptr->EndFlg){
			//情報セット
			SetCommInfo(ptr,  PKTHLN_CommPack_GetData(&data->SendShareData));
			return;
		}

		parent = PKTHLN_CommPack_GetData(&data->SendShareData);

		//親データは直接レシーバにセット
		{
			SHOT_CHILD_DATA *child;
			SHOT_CHILD_DATA *child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}

		{
			//プレーヤー数ループ
			for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
				SHOT_CHILD_DATA *child_data;
				SHOT_POKE *shot_poke;
				child_data = PKTHLN_CommPack_GetData(&data->ReciveData[i]);
				//タッチ状況を整理
				if (child_data->TouchValid){
					if ( (ptr->TpState[i].Trg)&&(ptr->TpState[i].Cont) ){
						ptr->TpState[i].Trg = FALSE;
					}else if((!ptr->TpState[i].Trg)&&(!ptr->TpState[i].Cont)){
						ptr->TpState[i].Trg = TRUE;
						ptr->TpState[i].Cont = TRUE;
					}
				}else{
					ptr->TpState[i].Trg = FALSE;
					ptr->TpState[i].Cont = FALSE;
				}

				if (ptr->TpState[i].Trg){
					u8 poke_no;
					//自分のポケモンをタッチしたかを検出
					poke_no = CheckPokeTouch(ptr, i, child_data->TpX, child_data->TpY);
					//自分のポケか？
					if ( (poke_no != SHOT_EVENT_POKE_NUM) ){
						shot_poke = &ptr->Poke[i][poke_no%ENTRY_MAX];
						//タッチしたポケは気絶ORダッシュ中ORノックバック中？
						if ( (shot_poke->State == SP_STATE_PANIC) ||
								( shot_poke->State == SP_STATE_DASH ) ||
								( shot_poke->KnockBack.Type != KNOCKBACK_NONE )){
							//タッチできない
							continue;
						}
						//ホールド登録
						ptr->HoldPokeNo[i] = poke_no;
						//ホールド時間カウント開始
						ptr->HoldTime = 0;
					}
				}else if (ptr->TpState[i].Cont){ //最終到達地点の上書き
					u8 poke_idx;
					//ホールドポケいなければ、処理しない
					if (ptr->HoldPokeNo[i] == SHOT_EVENT_POKE_NUM){
						continue;
					}
					//ホールド時間カウント
					if (ptr->HoldTime < HOLD_TIME_MAX ){
						ptr->HoldTime++;
					}
					poke_idx = ptr->HoldPokeNo[i]%ENTRY_MAX;
					shot_poke = &ptr->Poke[i][poke_idx];
					//目的ポイントの算出
					GetLastPoint(child_data->TpX, child_data->TpY, &shot_poke->LastPoint);
				}else{	//タッチしていない
					if ( ptr->HoldPokeNo[i] != SHOT_EVENT_POKE_NUM ){
						u8 poke_idx = ptr->HoldPokeNo[i]%ENTRY_MAX;
						shot_poke = &ptr->Poke[i][poke_idx];

						//気絶・疲労状態でないとき
						if ((shot_poke->State != SP_STATE_FATIGUE)&&
								(shot_poke->State != SP_STATE_PANIC)){
							//ダッシュ判定
							if (ptr->HoldTime <= HOLD_DASH_TIME){
								if ( (shot_poke->LastPoint.x != shot_poke->NowPoint.x) ||
									 (shot_poke->LastPoint.y != shot_poke->NowPoint.y)	){
									shot_poke->State = SP_STATE_DASH;
									//アクションポイント加算「ダッシュ回数」
									PTFrame_AddActionPoint(	work, i, ptr->HoldPokeNo[i]%ENTRY_MAX, ADD_TYPE_DASH, 1 );
								}
							}else{
								shot_poke->State = SP_STATE_NORMAL;
							}
						}
						//ホールド時間クリア
						ptr->HoldTime = 0;
						//ホールド解除
						ptr->HoldPokeNo[i] = SHOT_EVENT_POKE_NUM;

					}
				}
			}	//end for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++)

			//AI実行
#ifdef PM_DEBUG										//こっちデバッグ用
			if ( !DebugPkthlnWk.AI_Stop ){
				ShotAI_Execute(work, ptr->AICntPtr);
			}
#else												//こっち製品用
			ShotAI_Execute(work, ptr->AICntPtr);
#endif
		}

		//ポケモンの移動
		MovePoke(work);
		//ボールの移動
		MoveBall(work);
		//ポケモン・ボール接触判定
		HitBall(work);

		//ゴール判定
		CheckGoal(work);
		//疲労状態判定
		SetFatigue(work);

		//終了判定
		if (ptr->Timer <= 0){
			ptr->EndFlg = 1;
		}else{
			ptr->EndFlg = 0;
		}
		//情報セット
		SetCommInfo(ptr, parent);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	通信データセット
 * @param	ptr		ポケスロンアプリポインタ
 * @param	parent	親データ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetCommInfo(PKTHLN_SHOT_PTR ptr, SHOT_PARENT_DATA *parent)
{
	int i;
	int dirs, poke_sts, ball_sts;
	u8 header, total_score;
	dirs = 0;
	poke_sts = 0;
	ball_sts = 0;

	for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
		u8 x,y;
		u8 dir;
		u8 state;
		SHOT_POKE *shot_poke;
		shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		x = (shot_poke->NowPoint.x/FX32_ONE);
		y = (shot_poke->NowPoint.y/FX32_ONE);
		state  = shot_poke->State;
		dir = shot_poke->Dir - 1;		//0〜3の値に収める
		//データ格納
		parent->PokeX[i] = x;
		parent->PokeY[i] = y;

		dirs += ( dir<<(i*2) );
		poke_sts += (state<<(i*2));
	}

	for (i=0;i<BALL_MAX;i++){
		u8 x,y;
		SHOT_BALL * ball;
		ball = &ptr->Ball[i];
		x = (ball->Pos.x/FX32_ONE);
		y = GetCommBallY(ball);
		parent->BallX[i] = x;
		parent->BallY[i] = y;
		ball_sts += ( ball->State << (i*2) );
	}

	//今回送る合計得点データを決定
	{
		header = ptr->SendNetID;
		total_score = ptr->TotalScore[ptr->SendNetID];
		ptr->SendNetID = (ptr->SendNetID+1)%ENTRY_MEMBER_NUM_MAX;
	}
	parent->St1 = dirs;
	parent->St1 += (ball_sts << (SHOT_EVENT_POKE_NUM*2));
	parent->St1 += (header << (SHOT_EVENT_POKE_NUM*2+BALL_MAX*2));
	if (ptr->Ball[0].Type == BALL_TYPE_GOLD){
		parent->St1 += (1 << 30);
	}
	if (ptr->Ball[1].Type != BALL_NONE){
		parent->St1 += (1 << 31);
	}

	parent->St2 = 0;
	parent->St2 += poke_sts;
	parent->St2 += ptr->EndFlg << (SHOT_EVENT_POKE_NUM*2);
	parent->St2 += (total_score<<(1+SHOT_EVENT_POKE_NUM*2));
}

//----------------------------------------------------------------------------
/**
 *	@brief		描画座標関連セット関数
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetDraw(PKTHLN_PTR work)
{
	int i;
	int draw_x,draw_y;
	int score;
	u8 get_score_no;
	u8 gold;
	u8 two_ball;

	u8 my_net_id;

	COMM_EVENT_COMMON_DATA * data;
	SHOT_PARENT_DATA *parent;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	my_net_id = PTFrameGetCurrentID(work);

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);

	//トップ判定
	SetTopFlg(ptr);

	for (i=0;i<SHOT_EVENT_POKE_NUM;i++){
		int x,y;
		u8 dir;
		u8 poke_state;
		SHOT_POKE *shot_poke;
		CLACT_WORK_PTR clact_ptr;
		PCLACT_PTR	pclact_ptr;
		shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		pclact_ptr = PokeAct_GetPclActPtr(shot_poke->PokeActPtr);
		clact_ptr = PCLACT_GetClActWorkPtr(pclact_ptr);

		poke_state = (parent->St2 >> (i*2)) & 0x3;	//2ビットマスク

		{
			if (poke_state == SP_STATE_FATIGUE){	//疲労中
///				OS_Printf("%d:疲労状態\n",i);
				PkthlnClAct_SetActive(shot_poke->StateActPtr, TRUE, TRUE);
				PkthlnClAct_ChgAnmCheck(shot_poke->StateActPtr, 12);
			}else if (poke_state == SP_STATE_PANIC){	//気絶中
///				OS_Printf("%d:気絶状態\n",i);
				PkthlnClAct_SetActive(shot_poke->StateActPtr, TRUE, TRUE);
				PkthlnClAct_ChgAnmCheck(shot_poke->StateActPtr, 16);
				//再生終了していたら
				if( Snd_SePlayCheck(SE_THLON_RUNNING_OUT) == FALSE ){
					Snd_SePlay( SE_THLON_RUNNING_OUT );	//気絶SE
				}
			}else{
				PkthlnClAct_SetActive(shot_poke->StateActPtr, TRUE, FALSE);
			}
		}

		x = parent->PokeX[i];
		y = parent->PokeY[i];
		dir = ( (parent->St1 >> (i*2)) & 0x3 );	//2ビットマスク
		dir += 1;	//1〜4の値に復元
		//描画座標計算
		draw_x = x;
		draw_y = y;

///		OS_Printf("%d::通信で受け取ったデータ%d\n",i,dir);

		shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];

		//汗・ヒヨコ
		{
			VecFx32 mat = {0,0,0};
			const PKTHPOKE_PARAM * prm;

			mat.x = draw_x * FX32_ONE;
			mat.y = draw_y * FX32_ONE;
			//タッチタイプで汗の位置かえる
			prm = PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX);
			switch (prm->Touch){
			case 1:
				mat.y -= (8*FX32_ONE);
				break;
			case 2:
				mat.y -= (8*FX32_ONE);
				break;
			case 3:
				mat.y -= (16*FX32_ONE);
				break;
			default:
				GF_ASSERT(0);
			}
			PkthlnClAct_SetPos(shot_poke->StateActPtr, &mat);
		}
		//ダッシュエフェクト
		{
			if (poke_state == SP_STATE_DASH){
				if (shot_poke->DashEffWait == 0){
					VecFx32 vec = {0,0,0};
					int x,y;
					POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
					u8 idx = shot_poke->DashEffIdx;

					PokeAct_GetShadowPosByTouchPos(poke_ptr,
								parent->PokeX[i], parent->PokeY[i], &x, &y);

					vec.x = x * FX32_ONE;
					vec.y = y * FX32_ONE;

					PkthlnClAct_SetPos(shot_poke->DashActPtr[ idx ], &vec);
					PkthlnClAct_SetActive(shot_poke->DashActPtr[ idx ], TRUE, TRUE);
					PkthlnClAct_ChgAnm(shot_poke->DashActPtr[ idx ], 14);
					shot_poke->DashEffIdx = (shot_poke->DashEffIdx+1) % DASH_EFF_NUM;
					shot_poke->DashEffWait = DASH_EFF_WAIT;
					//自分のポケのときはＳＥ
					if ( i/ENTRY_MAX == my_net_id ){
						Snd_SePlay( SE_BOUND_DASH );
					}
				}else{
					shot_poke->DashEffWait--;
				}
			}
		}

		//ポケモン位置
		{
			POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);

			if ( poke_state == SP_STATE_PANIC ){
				//気絶アニメ
				PokeAct_SetAnm(poke_ptr, ANM_TYPE_PANIC);
			}else{
				//向きセット
				PokeAct_SetDir(poke_ptr, dir);
			}
			//アクター位置セット
			PokeAct_SetPosTouch(poke_ptr, x, y, TRUE);
		}
	}//end for


	{
		//自分のポケのプライオリティ変更
		SHOT_POKE *my_poke = &ptr->Poke[my_net_id][0];
		SortPpkePriority(my_poke, &parent->PokeY[my_net_id*ENTRY_MAX]);
		//他チームのポケプライオリティ変更
		SortEnemyPoke(ptr, parent, my_net_id);
	}

	gold = (parent->St1 >> 30) & 0x1;	//1ビットマスク
	two_ball = (parent->St1 >> 31) & 0x1;	//1ビットマスク

	//ボール・ゴール
	for(i=0;i<BALL_MAX;i++){
		u8 ball_state;
		VecFx32 vec = {0,0,0};
		SHOT_BALL *ball;
		ball = &ptr->Ball[i];
		ball_state = ( parent->St1 >> (SHOT_EVENT_POKE_NUM*2) );
		ball_state = ( ball_state >> (i*2) ) & 0x3;		//2ビットマスク
		if ( ball_state == BALL_STATE_GOAL ){
			BOOL gold_ball;
			//ボールバニッシュ
			PkthlnClAct_SetActive(ball->BallActPtr, TRUE, FALSE);
			//シュートエフェクトバニッシュ
			PkthlnClAct_SetActive(ball->EffActPtr, TRUE, FALSE);
			//ボールの場所によってゴールエフェクトの位置を決定
			if ( (i==0)&&gold ){
				gold_ball = TRUE;
			}else{
				gold_ball = FALSE;
			}
			SetGoalAnm(ptr, i, gold_ball, parent->BallX[i], parent->BallY[i], my_net_id);
		}else{
			ball->GoalEffFlg = 0;
			if ( i==1 ){
				if (two_ball){
					PkthlnClAct_SetActive(ball->BallActPtr, TRUE, TRUE);
				}else{
					PkthlnClAct_SetActive(ball->BallActPtr, TRUE, FALSE);
				}
			}else{
				PkthlnClAct_SetActive(ball->BallActPtr, TRUE, TRUE);
			}

			if ( ball_state == BALL_STATE_ATTACK ){
				PkthlnClAct_SetActive(ball->EffActPtr, TRUE, TRUE);
				if (ball->LocalState != BALL_STATE_ATTACK){
					//SE
					Snd_SePlay( SE_BOUND_BALL_EFF );
				}
			}else{
				PkthlnClAct_SetActive(ball->EffActPtr, TRUE, FALSE);
			}

			if ((i==0)&&gold){
				PkthlnClAct_ChgAnmCheck(ball->BallActPtr, 11);	//金玉
			}else{
				PkthlnClAct_ChgAnmCheck(ball->BallActPtr, 10);	//通常玉
			}
		}
		//ボールローカルステート更新
		ball->LocalState = ball_state;

		vec.x = parent->BallX[i] * FX32_ONE;
		vec.y = GetBallDispY(parent->BallY[i]);

		//ボール出現SE
		PlayBallAppSE(ptr, i, gold, parent->BallY[i]);

		PkthlnClAct_SetPos(ball->BallActPtr, &vec);
		PkthlnClAct_SetPos(ball->EffActPtr, &vec);
		if (parent->BallY[i]<BALL_FIELD){
			//プライオリティ
			PkthlnClAct_SetPriority(ball->BallActPtr, PRI_BALL);
		}else{
			//プライオリティ
			PkthlnClAct_SetPriority(ball->BallActPtr, PRI_ANM_BALL);
		}
	}//end for

	//ポストフラッシュ停止
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		if ( !PkthlnClAct_AnmActiveCheck(ptr->MyGoalActPtr[i]) ){
			//非表示にする
			PkthlnClAct_SetActive(ptr->PostFlashActPtr[i], 1, 0);
		}
	}

	//スコア更新処理
	{
		UpdataSubDispScore(work);
		//BGフィル
		score = ShotSub_GetDispScore(ptr->SubDispCntPtr);
		ShotSub_FillPoint(ptr->SubDispCntPtr, score);
	}

	//タイマー表示
	ShotSub_DispTime(ptr->SubDispCntPtr, ptr->Timer);

	//プレーヤー名プリント
	PrintPlayerName(ptr);

	//ラスト３秒
///	PTFrame_DispLastCount(work, ptr->Timer);		＜＜この競技では表示しない

}

//----------------------------------------------------------------------------
/**
 *	@brief	上画面スコア描画更新含まず
 *
 *	@param	work		ポケスロンワークポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void UpdataSubDispScore(PKTHLN_PTR work)
{
	COMM_EVENT_COMMON_DATA * data;
	SHOT_PARENT_DATA *parent;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	{
		u8 score;
		u8 recive_net_id;
		recive_net_id = (parent->St1 >> (SHOT_EVENT_POKE_NUM*2+BALL_MAX*2)) & 0x3;	//2ビットマスク
		score = (parent->St2 >> (1+SHOT_EVENT_POKE_NUM*2) ) & 0x7f;	//7ビットマスク

		//各プレーヤースコアを保存
		ptr->ScoreStoc[recive_net_id] = score;
		//自分のスコア表示更新
		ShotSub_ScoreUpdate(ptr->SubDispCntPtr, score, recive_net_id);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ゴールアニメ(ローカル処理)
 *
 *	@param	ptr			競技ワークポインタ
 *	@param	inBallIdx	ボールインデックス
 *	@param	inIsGold	金玉か？
 *	@param	inX			Ｘ座標
 *	@param	inY			Ｙ座標
 *	@param	inMyNetID	自分のネットＩＤ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SetGoalAnm(	PKTHLN_SHOT_PTR ptr, const u8 inBallIdx, const BOOL inIsGold,
						const u8 inX, const u8 inY, const u8 inMyNetID)
{
	SHOT_BALL *ball;
	u8 idx;
	u8 eff_idx;
	u8 owner;

	//所有者無しのボールのときの場合を考えY座標がGOAL_EFF_BASE_Y1未満の場合は演出なし
	if (inY<GOAL_EFF_BASE_Y1){
		return;
	}

	//通信データではなくローカルデータで処理
	ball = &ptr->Ball[inBallIdx];

	if (ball->GoalEffFlg){
		return;
	}else{
		ball->GoalEffFlg = 1;
	}

	//通信で送られてきたボールのＹ座標（ゴールエフェクト座標）からエフェクト位置を割り出す
	idx = inY - GOAL_EFF_BASE_Y1;	//0〜15
	GF_ASSERT(idx < 16);
	eff_idx = idx / ENTRY_MEMBER_NUM_MAX;	//0〜3

	PkthlnClAct_ChgAnm(ptr->GoalActPtr[eff_idx], 15);

	owner = idx%ENTRY_MEMBER_NUM_MAX;

	//加算者と減算者がいるか？
	if (owner != eff_idx){		//ともにいる
		//ゴールした人の名前を獲得点数表示にする
		u8 gold = 0;
		if ( inIsGold ){
			gold = 1;
		}
		ReqGoalEff(ptr, owner, 1, gold);
		//点数減算されるプレーヤー
		ReqGoalEff(ptr, eff_idx, 0, 0);
	}else{		//減算者のみ
		//点数減算されるプレーヤー
		ReqGoalEff(ptr, eff_idx, 0, 0);
	}

	//自殺点だった場合は以下の処理は行わない
	if ( ( 0 == idx%(ENTRY_MEMBER_NUM_MAX+1) ) &&
			( inMyNetID == idx/(ENTRY_MEMBER_NUM_MAX+1) ) ){
		//自殺点ＳＥ
		Snd_SePlay( SE_BOUND_WH );
		return;
	}

	//自分がゴールしたときのゴールエフェクト処理
	if(inMyNetID == owner){	//ゴールしたのが自分か？
		u8 anm_idx;
		//座標セット
		switch(eff_idx){
		case 0:
		case 2:
			anm_idx = MY_GOAL_ANM_OFS;
			break;
		case 1:
		case 3:
			anm_idx = MY_GOAL_ANM_OFS+1;
			break;
		default:
			GF_ASSERT(0);
			return;
		}
		//表示
		PkthlnClAct_SetActive(ptr->MyGoalActPtr[eff_idx], 1, 1);
		PkthlnClAct_ChgAnm(ptr->MyGoalActPtr[eff_idx], anm_idx);
		//ポストフラッシュ開始
		PkthlnClAct_SetActive(ptr->PostFlashActPtr[eff_idx], 1, 1);
		PkthlnClAct_ChgAnm(ptr->PostFlashActPtr[eff_idx], POST_FLASH_ANM_OFS+eff_idx);
		//自分ゴールＳＥ
		Snd_SePlay( SE_BOUND_WH_GOAL );
	}else{
		//他人ゴールＳＥ
		Snd_SePlay( SE_BOUND_WH );
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモン移動
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void MovePoke(PKTHLN_PTR work)
{
	int i,j;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);
	VecFx32 old_vec[SHOT_EVENT_POKE_NUM];
	VecFx32 zero_vec = {0,0,0};
	//ポケの移動
	for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
		fx32 move;
		SHOT_POKE *shot_poke;
		VecFx32 dir_vec;
		VecFx32 norm_dir_vec;
		fx32 len;
		VecFx32 temp_vec;


		shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		shot_poke->MoveDir = zero_vec;
		old_vec[i] = shot_poke->NowPoint;
		temp_vec = shot_poke->NowPoint;

		//ノックバック移動
		if (shot_poke->KnockBack.Type != KNOCKBACK_NONE){
			if ( (shot_poke->KnockBack.Type == KNOCKBACK_DAMAGE)||
					(shot_poke->KnockBack.Type == KNOCKBACK_GARD) ){
				if (shot_poke->KnockBack.Freeze > 0){
					shot_poke->KnockBack.Freeze--;
				}
			}

			if ( (shot_poke->KnockBack.Spd == 0)&&(shot_poke->KnockBack.Freeze <= 0) ){
				//処理終了
				shot_poke->KnockBack.Type = KNOCKBACK_NONE;
				shot_poke->KnockBack.Freeze = 0;
			}else{
				VEC_MultAdd( shot_poke->KnockBack.Spd*FX32_ONE, &shot_poke->KnockBack.Dir,
						&temp_vec, &temp_vec);
				shot_poke->NowPoint = temp_vec;
				shot_poke->LastPoint = shot_poke->NowPoint;
				if (shot_poke->KnockBack.Spd > 0){
					shot_poke->KnockBack.Spd--;
				}
				//ダメージノックバックの場合はスピンする
				if ((shot_poke->State != SP_STATE_PANIC)&&(shot_poke->KnockBack.Type == KNOCKBACK_DAMAGE)){
					UpdateDamageSpin(shot_poke);
				}
			}
		}

		//気絶中か？
		if ((shot_poke->State == SP_STATE_PANIC)||(shot_poke->PanicCount>0)){
			//気絶カウンタ減算
			shot_poke->PanicCount--;
			if (shot_poke->PanicCount == 0){
				//気絶回復
				shot_poke->State = SP_STATE_NORMAL;
				//スタミナ値最大
				shot_poke->Param.StaminaNow = shot_poke->Param.StaminaMax;
			}
			continue;
		}

		//ノックバック中は通常移動できない
		if (shot_poke->KnockBack.Type == KNOCKBACK_NONE){
			//方向ベクトル取得
			VEC_Subtract( &shot_poke->LastPoint, &temp_vec, &dir_vec );
			//方向ベクトルの長さを取得
			len = VEC_Mag(&dir_vec);

			//長さが0のときは処理を打ち切る
			if (len <= 0){		//動いていない
///				OS_Printf("%dを回復\n",i);
				//スタミナの回復
				RecoverStamina(shot_poke);
				continue;
			}
			//正規化
			VEC_Normalize(&dir_vec, &norm_dir_vec);

			//進行方向保存
			shot_poke->MoveDir = norm_dir_vec;

			if ( shot_poke->State == SP_STATE_DASH ){
				move = shot_poke->Param.MoveDash;
			}else if ( shot_poke->State == SP_STATE_FATIGUE ){
				move = FAT_MV_SPD * FX32_ONE;
			}else{
				move = shot_poke->Param.MoveWalk;
			}
			//方向ベクトルの長さが、スピード長以下ならば、次の加算で目的に到達する
			if (len <= move){
				temp_vec = shot_poke->LastPoint;
			}else{
				//スピード調整
				{
					VecFx32 add = {0,0,0};
					VEC_MultAdd( move, &norm_dir_vec, &add, &dir_vec);
					VEC_Add( &dir_vec, &temp_vec, &temp_vec);
				}
			}

			//方向ベクトルから、ポケモンの向きを決定する
			if (len != 0){
				//ZX平面で考える
				u16 rad;
				VecFx32 vec = {0,0,FX32_ONE};
				VecFx32 xz_vec;
				xz_vec.x = norm_dir_vec.y;
				xz_vec.z = norm_dir_vec.x;
				xz_vec.y = 0;

				rad = GetRad(&vec, &xz_vec);
///				OS_Printf("rad=%x\n",rad);
				if ( (0<=rad&&rad<=0x2000)||(0xe000<=rad) ){		//右
					shot_poke->Dir = POKE_DIR_RIGHT;
				}else if(0x2000<rad&&rad<0x6000){		//下
					shot_poke->Dir = POKE_DIR_DOWN;
				}else if(0x6000<=rad&&rad<=0xa000){		//左
					shot_poke->Dir = POKE_DIR_LEFT;
				}else{	//(0xa000<rad&&rad<0xe000)		//上
					shot_poke->Dir = POKE_DIR_UP;
				}
			}
			shot_poke->NowPoint = temp_vec;
		}	//end if (shot_poke->KnockBack.Type == KNOCKBACK_NONE)
	}	//end for

	for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
		SHOT_POKE *shot_poke;
		shot_poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		//壁判定
		{
			VecFx32 vec;
			HIT_CHECK rc;
			if ( (old_vec[i].x != shot_poke->NowPoint.x) || (old_vec[i].y != shot_poke->NowPoint.y) ){
///				OS_Printf("now_old = %d,%d_%d,%d\n",shot_poke->NowPoint.x, shot_poke->NowPoint.y, old_vec[i].x, old_vec[i].y);
				rc = WallHitCheck( &shot_poke->NowPoint, &old_vec[i], shot_poke->HitRange, TRUE, &vec );
				if (rc){
///					OS_Printf("hit_vec = %d,%d\n",vec.x, vec.y);
					shot_poke->NowPoint = vec;
					shot_poke->LastPoint = shot_poke->NowPoint;
				}
			}
		}
		//目的地到着?
		if ( (shot_poke->NowPoint.x == shot_poke->LastPoint.x)&&
			 (shot_poke->NowPoint.y == shot_poke->LastPoint.y) ){
			if ( (shot_poke->State != SP_STATE_FATIGUE)&&(shot_poke->State != SP_STATE_PANIC) ){
				shot_poke->State = SP_STATE_NORMAL;
			}
		}
	}
///	PushExecute(ptr);
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール接触判定
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void HitBall(PKTHLN_PTR work)
{
	int i,j;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	for (j=0;j<BALL_MAX;j++){
		int ball_r;
		SHOT_BALL *ball;
		ball = &ptr->Ball[j];

		//ボールタイプ未決定の場合は処理しない
		if ( ball->Type == BALL_NONE ){
			continue;
		}

		//ボールが蹴れる状態ではないときは処理しない
		if ( (ball->State != BALL_STATE_NORMAL) && (ball->State != BALL_STATE_ATTACK) ){
			continue;
		}

		if (ball->Type == BALL_TYPE_NORMAL){
			ball_r = NORM_BALL_RANGE;
		}else if(ball->Type == BALL_TYPE_GOLD){
			ball_r = GOLD_BALL_RANGE;
		}

		for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
			int poke_r;
			VecFx32 poke_vec = {0,0,0};
			SHOT_POKE *poke;
			poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];

			PokeAct_GetHitData(	poke->PokeActPtr, poke->NowPoint.x, poke->NowPoint.y,
								&poke_vec.x, &poke_vec.y, &poke_r );

			//ヒットチェック
			if ( CheckCircle(&poke_vec, poke_r*FX32_ONE, &ball->Pos, ball_r*FX32_ONE) ){
				//ヒット ボールの飛ぶ方向を決定
				VecFx32 dir_vec;
				u8 mv_val;
#if 1		//仕様変更でカット・・・したのだが、壁際で不動ポケがボールに触れていると他のポケが触れなくなるので、条件を追加して復活
				//接触判定ビットが立っていて、ボールが壁にヒットしたターンなら処理をスルー
				if (ball->Hit[i] && ball->WallHit){
					continue;
				}
#endif
				//受身ノックバック状態のポケはボールとのあたりを無視する
				if ( (poke->KnockBack.Type == KNOCKBACK_DAMAGE)||
						(poke->KnockBack.Type == KNOCKBACK_GARD) ){
					continue;
				}

				VEC_Subtract( &ball->Pos, &poke_vec, &dir_vec );
				//正規化
				VEC_Normalize(&dir_vec, &dir_vec);

				//ボールがアタック状態かで分岐
				if (ball->State == BALL_STATE_ATTACK){		//アタック
					int stamina;
					//ボールの所有権が自分なら、ヒットとみなさない
					if ( ball->Owner == i ){
						continue;
					}
					//スタミナ減らす
					stamina = poke->Param.StaminaNow;
					stamina -= ball->ShotPower;
					//スタミナが0以下になったか？
					if ( stamina <= 0 ){		//スタミナ0以下
						poke->Param.StaminaNow = 0;
						//気絶状態＆無条件で吹っ飛ぶ
						poke->State = SP_STATE_PANIC;
						poke->PanicCount = PANIC_TIME;
						//あたったポケはノックバック状態になる
						poke->KnockBack.Type = KNOCKBACK_DAMAGE;
						poke->KnockBack.Freeze = FREEZE_TIME;
						//ノックバック方向を決定
						poke->KnockBack.Dir = dir_vec;
						poke->KnockBack.Dir.x *= (-1);
						poke->KnockBack.Dir.y *= (-1);
						//ノックバックスピード決定
						poke->KnockBack.Spd = KNOCKBACK_VAL_DAMAGE;
						//アクションポイント加算「失敗回数」
						PTFrame_AddActionPoint(	work, i/ENTRY_MAX, i%ENTRY_MAX, ADD_TYPE_FAIL, 1 );
					}else{		//まだスタミナある
						///VecFx32 poke_vec;
						int rad;
						///BOOL range;

						poke->Param.StaminaNow = stamina;
						//ポケ→ボールの方向ベクトル取得
						///VEC_Subtract( &ball->Pos, &poke->NowPoint, &poke_vec );
						//ポケのシュートレンジを取得
						///rad = (poke->Param.GardRange * 0x10000) /360;
						//ガード角度かをチェック
						///range = CheckRotIO( &poke_vec, &dir_vec, rad );
						if (/*range*/0){	//ガード範囲か？  <<シュート状態のボールはどんなことがあってもはじけなくなった（仕様変更）
							//ボールはじく
							ChgBallDir(ptr, ball, &dir_vec);	//移動ベクトルセット
							//所有権移動
							ball->Owner = i;
							//触ったポケはノックバック状態になる
							poke->KnockBack.Type = KNOCKBACK_GARD;
							poke->KnockBack.Freeze = GARD_FREEZE_TIME;
							//ノックバックスピード決定
							poke->KnockBack.Spd = KNOCKBACK_VAL_GARD;
						}else{	//ダメージ吹っ飛び
							//触ったポケはノックバック状態になる
							poke->KnockBack.Type = KNOCKBACK_DAMAGE;
							poke->KnockBack.Freeze = FREEZE_TIME;
							//ノックバックスピード決定
							poke->KnockBack.Spd = KNOCKBACK_VAL_DAMAGE;
						}
						//ノックバック方向を決定
						poke->KnockBack.Dir = dir_vec;
						poke->KnockBack.Dir.x *= (-1);
						poke->KnockBack.Dir.y *= (-1);
					}
				}else{		//非アタック
					//ポケモンが静止しているかで分岐
					if ( VEC_Mag(&poke->MoveDir)!=0/*(poke->NowPoint.x != poke->LastPoint.x)||
							(poke->NowPoint.y != poke->LastPoint.y)*/ ){	//静止していない
///						VecFx32 poke_vec;
						BOOL range;
						u32 rad;
						//シュート判定
						//方向ベクトル取得
///						VEC_Subtract( &poke->LastPoint, &poke->NowPoint, &poke_vec );
						//ポケのシュートレンジを取得
						rad = (poke->Param.ShotRange * 0x10000) /360;
						//シュート角度かをチェック
						range = CheckRotIO( &poke->MoveDir, &dir_vec, rad );
						if ( (poke->State == SP_STATE_DASH) && range ){
							//ボールの状態セット
							ball->State = BALL_STATE_ATTACK;
							ball->MvType = BALL_MV_TYPE_SHOT;
							ball->MvValIdx = poke->Param.Technique;
							//ボールにパワーをセット
							ball->ShotPower = poke->Param.ShotPower;
							ball->Power = poke->Param.Power;

							mv_val = ShotMvVal[ball->MvValIdx][0];
							//シュート打ったポケはノックバック状態になる
							poke->KnockBack.Type = KNOCKBACK_ATTACK;
							//ノックバック方向を決定
							poke->KnockBack.Dir = dir_vec;
							poke->KnockBack.Dir.x *= (-1);
							poke->KnockBack.Dir.y *= (-1);
							//ノックバックスピード決定
							poke->KnockBack.Spd = KNOCKBACK_VAL_ATTACK;
							//ポケモンステート更新
							poke->State = SP_STATE_NORMAL;
							//移動フレームセット
							ball->MvFrame = 1;
							ball->MvFrameMax = BALL_MV_FRAME_S;
							//アクションポイント加算「体当たり回数」
							PTFrame_AddActionPoint(	work, i/ENTRY_MAX, i%ENTRY_MAX, ADD_TYPE_ATTACK, 1 );
						}else{
							ball->MvType = BALL_MV_TYPE_DRIBBLE;
							ball->MvValIdx = poke->Param.Technique;
///							OS_Printf("teq = %d\n",poke->Param.Technique);
							mv_val = DribbleMvVal[ball->MvValIdx][0];
							//移動フレームセット
							ball->MvFrame = 1;
							ball->MvFrameMax = BALL_MV_FRAME_D;
						}
						//飛ぶスピードセット
						ball->MvVal = mv_val;
					}
					//移動ベクトルセット
					ChgBallDir(ptr, ball, &dir_vec);
					//所有権セット
					ball->Owner = i;
				}
				//接触判定用ビットON
				ball->Hit[i] = 1;
			}else{
				//接触判定用ビットOFF
				ball->Hit[i] = 0;
			}
		}
		//ポストとのヒット判定
		for(i=0;i<GPOST_NUM*ENTRY_MEMBER_NUM_MAX;i++){
			const VecFx32 *post_vec;
			post_vec = &gpost_vec[i%ENTRY_MEMBER_NUM_MAX][i/ENTRY_MEMBER_NUM_MAX];
			//ヒットチェック
			if ( CheckCircle(post_vec, GPOST_RANGE*FX32_ONE, &ball->Pos, ball_r*FX32_ONE) ){
				VecFx32 dir_vec;
				fx32 dot_prdct;
				fx32 scl;
				//ボールからポスト中心へのcベクトルを求める
				VEC_Subtract( post_vec, &ball->Pos, &dir_vec );
				//cベクトル正規化
				VEC_Normalize(&dir_vec, &dir_vec);
				//ボールの方向ベクトルとcベクトルの内積を求める
				dot_prdct = VEC_DotProduct(&ball->MoveVec, &dir_vec);
				if (dot_prdct <= 0){
					//ボールがポストに向かっていないので処理打ち切り
					OS_Printf("ボールがポストに向かっていないので処理しない\n");
					break;
				}
				scl = dot_prdct * (-2);
				//ｃベクトルを-2倍（逆方向に２倍）してボール方向ベクトルにcベクトルを足す
				VEC_MultAdd( scl, &dir_vec, &ball->MoveVec, &ball->MoveVec);
				//ボールの方向ベクトルを正規化
				VEC_Normalize(&ball->MoveVec, &ball->DirVec);
				break;
			}
		}	//end for(i=0;i<GPOST_NUM*ENTRY_MEMBER_NUM_MAX;i++){
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール移動
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void MoveBall(PKTHLN_PTR work)
{
	int i,j;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	//2個ボールを出していいタイムか?
	if ( (ptr->Ball[1].Type == BALL_NONE)&&(ptr->Timer <= TWO_BALL_TIME) ){
		//2個目セット
		ptr->Ball[1].State = BALL_STATE_READY;
		ptr->Ball[1].Type = BALL_TYPE_NORMAL;
	}

	for(i=0;i<BALL_MAX;i++){
		SHOT_BALL *ball;
		ball = &ptr->Ball[i];

		//ボールタイプ未決定の場合は処理しない
		if ( ball->Type == BALL_NONE) {
			continue;
		}

		//ボール出現処理
		if (ball->State == BALL_STATE_READY){
			ball->AppCount++;
			if (ball->AppCount>=BALL_APP_COUNT){
				ball->AppCount = 0;
				ball->State = BALL_STATE_NORMAL;
			}
			continue;
		}

		if (ball->State == BALL_STATE_GOAL){
			ball->GoalCounter--;
			if (ball->GoalCounter == 0){
				ResetBall(ball);
				//ボールを生成
				GenerateBall(ptr, ball);
				//ボールのタイプを抽選(インデックス0番のボールのみ)
				if (i == 0){
					u8 prob = 0;
					if (ptr->Timer >= GOLD_BALL_TIME1){
						prob = GOLD_BALL_PROB1;
					}else if(ptr->Timer >= GOLD_BALL_TIME2){
						prob = GOLD_BALL_PROB2;
					}else if(ptr->Timer >= GOLD_BALL_TIME3){
						prob = GOLD_BALL_PROB3;
					}else{
						prob = GOLD_BALL_PROB4;
					}

					//キャリーオーバー分
					prob += ptr->GoldProbPlus;
					if (prob > 100){
						prob = 100;
					}
					//抽選
					if ( gf_rand()%100 < prob ){
						//金玉抽選
						ball->Type = BALL_TYPE_GOLD;
						ptr->GoldProbPlus = 0;
					}else{
						//通常玉抽選
						ball->Type = BALL_TYPE_NORMAL;
						if (ptr->GoldProbPlus < 100){
							//キャリーオーバー
							ptr->GoldProbPlus++;
						}
					}
				}else{
					ball->Type = BALL_TYPE_NORMAL;
				}
			}
		}else{
			fx32 len;

			//ボールが蹴れる状態ではないときは処理しない
			if ( (ball->State != BALL_STATE_NORMAL) && (ball->State != BALL_STATE_ATTACK) ){
				continue;
			}

			len = ball->MvVal * FX32_ONE;
			if ( len != 0 ){
				VecFx32 old_pos;
				old_pos = ball->Pos;
				ball->Pos.x += ball->MoveVec.x;
				ball->Pos.y += ball->MoveVec.y;
				//ボールが攻撃状態かを調べて、状態セット
//				OS_Printf("pw = %d ats = %d\n",ball->Power, AttackSpeed[ball->Power]);
				if ( len >= AttackSpeed[ball->Power]*FX32_ONE ){
					if (ball->MvType == BALL_MV_TYPE_SHOT){
						ball->State = BALL_STATE_ATTACK;
					}else{
						ball->State = BALL_STATE_NORMAL;
					}
				}else{
					ball->State = BALL_STATE_NORMAL;
					ball->ShotPower = 0;//スタミナを減らす力をクリア
				}
				//ボール速度更新
				{
					u8 mv_val;
					u8 frame;
					VecFx32 zero_vec = {0,0,0};

					frame = ball->MvFrame;
					if ( ball->MvType == BALL_MV_TYPE_SHOT ){
						mv_val = ShotMvVal[ball->MvValIdx][frame];
					}else if ( ball->MvType == BALL_MV_TYPE_DRIBBLE ){
						mv_val = DribbleMvVal[ball->MvValIdx][frame];
					}else{
						GF_ASSERT(0);
						mv_val = 0;
					}
					//スピードセット
					ball->MvVal = mv_val;
//					OS_Printf("move_val = %d\n",ball->MvVal);
					//次の移動ベクトルをセット
					ChgBallDir(ptr, ball, &ball->DirVec);

					ball->MvFrame++;
					if (ball->MvFrame >= ball->MvFrameMax){
						ball->MoveVec.x = 0;
						ball->MoveVec.y = 0;
						ball->DirVec = zero_vec;
						ball->MvType = BALL_MV_TYPE_NONE;
						ball->MvVal = 0;
					}else if ( ball->MvVal ==0 ){
						ball->DirVec = zero_vec;
						ball->MvFrame = 0;
						ball->MvFrameMax = 0;
						ball->MvType = BALL_MV_TYPE_NONE;
					}
				}

				ball->WallHit = FALSE;

				//壁チェック
				{
					VecFx32 vec;
					HIT_CHECK rc;
					rc = WallHitCheck(	&ball->Pos, &old_pos, NORM_BALL_RANGE, FALSE, &vec );
					if (rc){
						ball->Pos = vec;
						ball->WallHit = TRUE;
					}
					switch(rc){
					case HIT_U:
					case HIT_D:
						ball->DirVec.y *= (-1);
						ball->MoveVec.y *= (-1);
						break;
					case HIT_L:
					case HIT_R:
						ball->DirVec.x *= (-1);
						ball->MoveVec.x *= (-1);
						break;
					}
				}
			}else{
				ball->State = BALL_STATE_NORMAL;
				//パワー設定オフ
				ball->ShotPower = 0;
				ball->Power = 0;
				ball->MvType = BALL_MV_TYPE_NONE;
			}//end if ( len != 0 )
		}		//end if ( ball->State == BALL_STATE_GOAL )
	}

	//2個ボールが無い場合はここで終了
	if ( (ptr->Ball[0].Type == BALL_NONE) || (ptr->Ball[1].Type == BALL_NONE) ){
		return;
	}

	//ボール同士の当たり判定
	{
		SHOT_BALL *ball1;
		SHOT_BALL *ball2;
		int r1,r2;
		ball1 = &ptr->Ball[0];
		ball2 = &ptr->Ball[1];

		//衝突しない状態にあるときは処理しない
		if ( (ball1->State == BALL_STATE_GOAL)||(ball1->State == BALL_STATE_READY) ){
			return;
		}
		if ( (ball2->State == BALL_STATE_GOAL)||(ball2->State == BALL_STATE_READY) ){
			return;
		}

		//1つめのボール半径をセット
		if (ball1->Type == BALL_TYPE_NORMAL){
			r1 = NORM_BALL_RANGE;
		}else if(ball1->Type == BALL_TYPE_GOLD){
			r1 = GOLD_BALL_RANGE;
		}else{
			GF_ASSERT(0);
			return;
		}
		//2つめのボール半径をセット
		r2 = NORM_BALL_RANGE;

		if ( CheckCircle(&ball1->Pos, r1*FX32_ONE, &ball2->Pos, r2*FX32_ONE) ){
			//2つのボールの情報をスイッチする
			SwitchBallInfo(ball1, ball2);
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール情報のスイッチ
 *
 *	@param	ball1		ボール1
 *	@param	ball2		ボール2
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SwitchBallInfo( SHOT_BALL *ball1, SHOT_BALL *ball2 )
{
	SHOT_BALL ball;

	ball.MoveVec = ball1->MoveVec;
	ball.DirVec = ball1->DirVec;
	ball.State = ball1->State;
	ball.Owner = ball1->Owner;
	ball.MvFrame = ball1->MvFrame;
	ball.MvFrameMax = ball1->MvFrameMax;
	ball.MvType = ball1->MvType;
	ball.MvVal = ball1->MvVal;
	ball.MvValIdx = ball1->MvValIdx;
	ball.Pos = ball1->Pos;

	SwitchBallInfoCore( ball1, ball2, 0 );
	SwitchBallInfoCore( ball2, &ball, 1 );
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール情報のスイッチ(逆方向に飛ぶようにスイッチする)
 *
 *	@param	my_ball		自分ボール
 *	@param	target_ball		相手ボール
 *	@param	inIdx			ボールインデックス
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SwitchBallInfoCore( SHOT_BALL *my_ball, const SHOT_BALL *target_ball, const u8 inIdx )
{
	VecFx32 zero_vec = {0,0,0};
	//相手のボールスピードをもらうかをチェック
	if ( my_ball->MvVal <= RESTART_VAL ){	//もらう
		//もらった結果、規定速度以上あるか？
		if (target_ball->MvVal > RESTART_VAL){
			//速度もらう
			my_ball->State = target_ball->State;
			my_ball->MvFrame = target_ball->MvFrame;
			my_ball->MvFrameMax = target_ball->MvFrameMax;
			my_ball->MvType = target_ball->MvType;
			my_ball->MvVal = target_ball->MvVal;
			my_ball->MvValIdx = target_ball->MvValIdx;
		}else{
			//再スタートテーブルの速度を設定
			my_ball->State = BALL_STATE_NORMAL;
			my_ball->MvFrame = 0;
			my_ball->MvFrameMax = RESTART_FRAME;
			my_ball->MvType = BALL_MV_TYPE_DRIBBLE;
			my_ball->MvVal = RestartMvVal[0];
			my_ball->MvValIdx = 0;
		}
	}else{
		//再スタートテーブルの速度を設定
		my_ball->State = BALL_STATE_NORMAL;
		my_ball->MvFrame = 0;
		my_ball->MvFrameMax = RESTART_FRAME;
		my_ball->MvType = BALL_MV_TYPE_DRIBBLE;
		my_ball->MvVal = RestartMvVal[0];
		my_ball->MvValIdx = 0;
	}

	//方向セット
	VEC_Subtract( &my_ball->Pos, &target_ball->Pos, &my_ball->DirVec );

	//方向が０ベクトルか？
	if (VEC_Mag(&my_ball->DirVec) == 0){
		const VecFx32 up_vec = {0,-FX32_ONE,0};
		const VecFx32 down_vec = {0,FX32_ONE,0};
		if (inIdx == 0){
			my_ball->DirVec = up_vec;
		}else{
			my_ball->DirVec = down_vec;
		}
	}
	//正規化
	VEC_Normalize(&my_ball->DirVec, &my_ball->DirVec);
	//移動ベクトルセット
	VEC_MultAdd( my_ball->MvVal*FX32_ONE, &my_ball->DirVec, &zero_vec, &my_ball->MoveVec );

	//相手の所有権をもらう（あるときのみ）
	if (target_ball->Owner < SHOT_EVENT_POKE_NUM){
		my_ball->Owner = target_ball->Owner;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ゴールチェック
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void CheckGoal(PKTHLN_PTR work)
{
	int i;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);

	for(i=0;i<BALL_MAX;i++){
		u8 rc;
		u8 goal_idx;
		Vec2DS32 ball_vec;
		SHOT_BALL *ball;
		ball = &ptr->Ball[i];

		//ボールタイプ未決定の場合は処理しない
		if ( ball->Type == BALL_NONE ){
			continue;
		}
		//ボールが蹴れる状態ではないときは処理しない
		if ( (ball->State != BALL_STATE_NORMAL) && (ball->State != BALL_STATE_ATTACK) ){
			continue;
		}
		ball_vec.x = ball->Pos.x/FX32_ONE;
		ball_vec.y = ball->Pos.y/FX32_ONE;

		//ゴールインデックス取得
		goal_idx = GetGoalIdx(ball);

		rc = BG2D_VectorSideS32( &GoalVec[goal_idx][0], &GoalVec[goal_idx][1], &ball_vec );
		if (rc){
			SHOT_POKE *poke;
///			OS_Printf("%d:ゴール\n",i);

			//ボールをゴール状態に
			ball->State = BALL_STATE_GOAL;
			//ゴール状態カウンタセット
			ball->GoalCounter = GOAL_COUNT_MAX;
#ifdef PM_DEBUG
			//デバッグ。オーナーを無しにする
///			ball->Owner = SHOT_EVENT_POKE_NUM;
#endif
			if ( ball->Owner != SHOT_EVENT_POKE_NUM ){
				poke = &ptr->Poke[ball->Owner/ENTRY_MAX][ball->Owner%ENTRY_MAX];
				//オウンゴールチェック
				if (goal_idx == ball->Owner/ENTRY_MAX){		//オウンゴール
					//ボールオーナーに得点減算
					if (poke->Score){
						poke->Score--;
					}
					if ( ptr->TotalScore[ball->Owner/ENTRY_MAX] ){
						ptr->TotalScore[ball->Owner/ENTRY_MAX]--;
					}
					//アクションポイント加算「自滅回数」
					PTFrame_AddActionPoint(	work, ball->Owner/ENTRY_MAX, ball->Owner%ENTRY_MAX, ADD_TYPE_OWN, 1 );
					//アクションポイント加算「失敗回数」
					PTFrame_AddActionPoint(	work, ball->Owner/ENTRY_MAX, ball->Owner%ENTRY_MAX, ADD_TYPE_FAIL, 1 );

				}else{
					u8 plus = 0;
					if (ball->Type == BALL_TYPE_NORMAL){
						plus = 1;
					}else if (ball->Type == BALL_TYPE_GOLD){
						plus = 2;
					}else{
						GF_ASSERT(0);
					}
					//ボールオーナーに得点加算
					if (poke->Score+plus <= SHOT_SCORE_MAX){
						poke->Score += plus;
					}
					if ( ptr->TotalScore[ball->Owner/ENTRY_MAX]+plus <= SHOT_SCORE_MAX){
						ptr->TotalScore[ball->Owner/ENTRY_MAX] += plus;
					}
					//ゴール取られたチーム減算
					if ( ptr->TotalScore[goal_idx] ){
						ptr->TotalScore[goal_idx] --;
					}
					//アクションポイント加算「得点回数」
					PTFrame_AddActionPoint(	work, ball->Owner/ENTRY_MAX, ball->Owner%ENTRY_MAX, ADD_TYPE_GET, 1 );
				}
			}else{
				OS_Printf("所有権なしのボールがゴールした\n");
			}
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	疲労状態セット
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SetFatigue(PKTHLN_PTR work)
{
	u8 i;
	PKTHLN_SHOT_PTR ptr = PTFrame_GetEventWorkPtr(work);
	for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
		SHOT_POKE *poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		if (  poke->State != SP_STATE_PANIC){
			if (poke->Param.StaminaNow < FATIGUE_VAL){
				poke->State = SP_STATE_FATIGUE;
			}else if ( poke->State != SP_STATE_DASH ){
				poke->State = SP_STATE_NORMAL;
			}
		}
	}
}


//----------------------------------------------------------------------------
/**
 *	@brief	最終目的地取得
 *
 *	@param	inTpX		タッチＸ座標
 *	@param	inTpY		タッチＹ座標
 *	@param	*outPoint	最終目的ポイント
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void GetLastPoint(const u8 inTpX, const u8 inTpY, VecFx32 *outPoint)
{
	outPoint->x = inTpX*FX32_ONE;
	outPoint->y = inTpY*FX32_ONE;
	outPoint->z = 0;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモンをタッチしているかを判定する
 *
 *	@param	ptr		競技ポインタ
 *	@param	inNetID	ネットID
 *	@param	inX		X座標
 *	@param	inY		Y座標
 *
 *	@return u8 タッチしたポケモンインデックス
 */
//-----------------------------------------------------------------------------
static u8 CheckPokeTouch(PKTHLN_SHOT_PTR ptr, const u8 inNetID, const u16 inX, const u16 inY)
{
	u8 i;
	u8 touch_list[ENTRY_MAX];
	fx32 touch_range[ENTRY_MAX];
	u8 hit_num;
	u8 target;
	int base_range;
	fx32 now_range;

	base_range = PTFrame_GetPokeTouchRange();
	now_range = base_range*FX32_ONE;
	hit_num =0;
	//タッチしているポケモンのリストを作成
	for (i=0;i<ENTRY_MAX;i++){
		fx32 range;
		int x,y;
		SHOT_POKE *shot_poke;
		shot_poke = &ptr->Poke[inNetID][i];

		x = shot_poke->NowPoint.x / FX32_ONE;
		y = shot_poke->NowPoint.y / FX32_ONE;

		if ( PTFrame_CheckTouchRange( x, y, inX, inY, base_range, &range) ){
			//タッチ
			touch_range[i] = range;
			touch_list[i] = 1;
			hit_num++;
		}else{
			touch_range[i] = 0;
			touch_list[i] = 0;
		}
	}

	if (hit_num == 0){
		return SHOT_EVENT_POKE_NUM;		//タッチ範囲外
	}

	target = ENTRY_MAX;
	for (i=0;i<ENTRY_MAX;i++){
		if (touch_list[i]){
			if (touch_range[i] < now_range){
				target = i;
				now_range = touch_range[i];
			}
		}
	}
	if (target==ENTRY_MAX){
		GF_ASSERT(0);
		return SHOT_EVENT_POKE_NUM;
	}

	return target;

#if 0
	for(i=0;i<ENTRY_MAX;i++){
		SHOT_POKE *shot_poke;
		shot_poke = &ptr->Poke[inNetID][i];

		if ( PokeAct_CheckTouch(shot_poke->PokeActPtr,
					shot_poke->NowPoint.x, shot_poke->NowPoint.y, inX, inY) ){
			//タッチしている
			OS_Printf("%dのポケにタッチ\n",i);
			return (inNetID*ENTRY_MAX + i);
		}
	}
	return SHOT_EVENT_POKE_NUM;
#endif
}

//----------------------------------------------------------------------------
/**
 *	@brief	円同士の当たり判定
 *
 *	@param	inVec1		座標ベクタ1
 *	@param	inRange1	半径1
 *	@param	inVec2		座標ベクタ2
 *	@param	inRange2	半径2
 *
 *	@return BOOL	TRUEでヒット
 */
//-----------------------------------------------------------------------------
static BOOL CheckCircle(const VecFx32 *inVec1, const fx32 inRange1,
		const VecFx32 *inVec2, const fx32 inRange2)
{
	fx32 len;
	VecFx32 vec;

	VEC_Subtract( inVec1, inVec2, &vec );

	//方向ベクトルの長さを取得
	len = VEC_Mag(&vec);

	if (len <= inRange1+inRange2){
		return TRUE;
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	円同士の当たり判定
 *
 *	@param	* poke1	ポケ1
 *	@param	* poke2	ポケ2
 *
 *	@return	TRUEでヒット
 */
//-----------------------------------------------------------------------------
static BOOL CheckPokeCircle(SHOT_POKE * poke1, SHOT_POKE * poke2)
{
	int r1;
	int r2;
	fx32 len;
	VecFx32 vec, vec1, vec2;
	fx32 range;

	PokeAct_GetHitData(poke1->PokeActPtr,
			poke1->NowPoint.x, poke1->NowPoint.y, &vec1.x, &vec1.y, &r1);
	PokeAct_GetHitData(poke2->PokeActPtr,
			poke2->NowPoint.x, poke2->NowPoint.y, &vec2.x, &vec2.y, &r2);

	range = (r1+r2)*FX32_ONE;

	vec1.z = 0;
	vec2.z = 0;

	VEC_Subtract( &vec1, &vec2, &vec );
	//方向ベクトルの長さを取得
	len = VEC_Mag(&vec);

	if (len <= range){
		return TRUE;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボールデータリセット
 *
 *	@param	ball
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void ResetBall(SHOT_BALL *ball)
{
	u8 i;
	VecFx32 zero_vec = {0,0,0};
	ball->MoveVec = zero_vec;
	ball->DirVec = zero_vec;
	ball->Type = BALL_NONE;
	ball->State = BALL_STATE_READY;
	ball->GoalCounter = 0;
	ball->Owner = SHOT_EVENT_POKE_NUM;
	ball->MvFrame = 0;
	ball->MvFrameMax = 0;
	ball->MvType = BALL_MV_TYPE_NONE;
	ball->MvVal = 0;
	ball->MvValIdx = 0;
	ball->AppCount = 0;
	ball->ShotPower = 0;
	ball->Power = 0;
	for (i=0;i<SHOT_EVENT_POKE_NUM;i++){
		ball->Hit[i] = 0;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボールの方向を変える
 *
 *  @param	ptr			競技ポインタ
 *	@param	ball		ボール
 *	@param	inDirVec	方向ベクトル
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void ChgBallDir(PKTHLN_SHOT_PTR ptr, SHOT_BALL *ball, const VecFx32 *inDirVec)
{
	VecFx32 zero_vec = {0,0,0};
#if 0
	//8方向補正
	ball->DirVec = FixBallDir(ptr, inDirVec );
#else
	VEC_Normalize(inDirVec, &ball->DirVec);
#endif
	ball->MoveVec = ball->DirVec;

	VEC_MultAdd( ball->MvVal*FX32_ONE, &ball->MoveVec, &zero_vec, &ball->MoveVec );
}

//----------------------------------------------------------------------------
/**
 *	@brief	推進ベクトルを分解して子に引き継ぐ
 *
 *	@param	*inVec1		入力ベクトル1
 *	@param	*inVec2		入力ベクトル2
 *	@param	*outVec		移動ベクトル
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void CalcVec(const VecFx32 *inVec1, const VecFx32 *inVec2, VecFx32 *outVec)
{
	VecFx32 vec1,vec2;
	fx32 cos,len1,len2;

	VEC_Normalize(inVec1, &vec1);
	VEC_Normalize(inVec2, &vec2);

	cos = VEC_DotProduct(&vec1, &vec2);
	len1 = VEC_Mag(inVec1);
	len2 = FX_Mul(cos, len1);
	{
		VecFx32 vec = {0,0,0};
		VEC_MultAdd( len2, &vec2, &vec, outVec);
	}
///	OS_Printf("length = %x:%x\n",len1,len2);
}

//----------------------------------------------------------------------------
/**
 *	@brief	コサイン取得
 *
 *	@param	inVec1	ベクトル1
 *	@param	inVec2	ベクトル2
 *
 *	@return fx32 コサイン
 */
//-----------------------------------------------------------------------------
static fx32 GetCos( const VecFx32 *inVec1, const VecFx32 *inVec2 )
{
	VecFx32 vec1,vec2;

	VEC_Normalize(inVec1, &vec1);
	VEC_Normalize(inVec2, &vec2);

	return VEC_DotProduct(&vec1, &vec2);
}

//----------------------------------------------------------------------------
/**
 *	@brief	サイン取得
 *
 *	@param	inVec1	ベクトル1
 *	@param	inVec2	ベクトル2
 *
 *	@return fx32 サイン
 */
//-----------------------------------------------------------------------------
static fx32 GetSin( const VecFx32 *inVec1, const VecFx32 *inVec2 )
{
	VecFx32 vec1,vec2;
	fx32 val1, val2;

	VEC_Normalize(inVec1, &vec1);
	VEC_Normalize(inVec2, &vec2);
	val1 = FX_Mul(vec1.x, vec2.y);
	val2 = FX_Mul(vec2.x, vec1.y);
	return val1 - val2;
}

//----------------------------------------------------------------------------
/**
 *	@brief	2つのベクトルの挟角が指定角度内（+-どちらでも可）かを調べる
 *
 *	@param	inVec1	ベクトル1
 *	@param	inVec2	ベクトル2
 *	@param	inRad	指定角度
 *
 *	@return BOOL
 */
//-----------------------------------------------------------------------------
static BOOL CheckRotIO( const VecFx32 *inVec1, const VecFx32 *inVec2, const u16 inRad )
{
	fx32 cos;
	cos = GetCos( inVec1, inVec2 );

	if ( cos >= FX_CosIdx(inRad) ){
		return TRUE;
	}
	return FALSE;
}

#if 0
//----------------------------------------------------------------------------
/**
 *	@brief	得点取得判定
 *
 *	@param	ptr		競技ポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void CheckScore(PKTHLN_SHOT_PTR ptr)
{
	int i;
	u8 point;
	u8 ring_no;

	u8 point_hash[RING_MAX][SHOT_EVENT_POKE_NUM];
	u8 score_hash[RING_MAX];
	u8 ring_idx[RING_MAX];

	if (!ptr->AddScoreReq){
		return最大;
	}

	for(i=0;i<RING_MAX;i++){
		ring_idx[i] = 0;
	}

	ptr->AddScoreReq = 0;

///	OS_Printf("リング内外判定と得点加算\n");

	//ポイントリスト初期化(配列数をクリア)
	ptr->PointUpNumMax = 0;
	ptr->PointUpNum = 0;

	for(i=0;i<SHOT_EVENT_POKE_NUM;i++){
		SHOT_POKE *poke = &ptr->Poke[i/ENTRY_MAX][i%ENTRY_MAX];
		if (poke->State == POKE_ALIVE){
			int x,y;
			int sx,sy;
			//影の位置を取得
			x = poke->NowPoint.x/FX32_ONE;
			y = poke->NowPoint.y/FX32_ONE;
			PokeAct_GetShadowPosByTouchPos(poke->PokeActPtr, x, y, &sx, &sy);
			point = PtRing_GetPoint(ptr->NowFieldType,
					sx, sy, &ring_no);
			if (point){
				poke->Score+=point;
				point_hash[ring_no][ ring_idx[ring_no]++ ] = i;
				score_hash[ring_no] = point;
			}
		}
	}

	for(i=0;i<RING_MAX;i++){
		int j;
		for(j=0;j<ring_idx[i];j++){
			//ポイントリストに格納
			ptr->PointUpList[ptr->PointUpNumMax] = point_hash[i][j];
			ptr->PointList[ptr->PointUpNumMax] = score_hash[i];
			ptr->PointUpNumMax++;
		}
	}
}
#endif
/**
static void AddFixVec(const VecFx32 *inVec1, const VecFx32 *inVec2, VecFx32 *outVec)
{
	VecFx32 vec1,vec2;
	fx32 cos,len1,len2;

	VEC_Normalize(inVec1, &vec1);
	VEC_Normalize(inVec2, &vec2);

	cos = VEC_DotProduct(&vec1, &vec2);
	len1 = VEC_Mag(inVec1);
	len2 = FX_Mul(cos, len1);

	//長さを検査する。長ければ、上書き（加算じゃない）
	if ( len2 > VEC_Mag(inVec2) ){
		;
	}else{
		VEC_MultAdd( len2, &vec2, &vec, outVec);
	}

	{
		VecFx32 vec = {0,0,0};
		VEC_MultAdd( len2, &vec2, &vec, outVec);
	}


	;
	OS_Printf("length = %x:%x\n",len1,len2);
}*/

//--------------------------------------------------------------------------------------------
/**
 *　スタミナ回復
 *
 * @param	outPoke		対象ポケデータポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void RecoverStamina(SHOT_POKE *outPoke)
{
	outPoke->RcvTime++;
	if (outPoke->RcvTime >= ST_RCV_SPD){
		outPoke->RcvTime = 0;
		outPoke->Param.StaminaNow += ST_RCV_VAL;
///		OS_Printf("stn_stm = %d,%d\n", outPoke->Param.StaminaNow, outPoke->Param.StaminaMax);
		if (outPoke->Param.StaminaNow > outPoke->Param.StaminaMax){
			outPoke->Param.StaminaNow = outPoke->Param.StaminaMax;
		}
	}
}

//--------------------------------------------------------------------------------------------
/**
 * パラメータセット
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*inData		パラメータ
 * @param	inNetID		ネットＩＤ
 * @param	inIdx		ポケモンエントリーインデックス0〜2
 * @param	*outPoke	パラメータ格納場所
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetPokeParam(	PKTHLN_PTR work, const SHOT_PARAM *inData,
							const u8 inNetID, const u8 inIdx, SHOT_POKE *outPoke)
{
	const POKE_SPEC *spec;
	spec = PTFrame_GetPokeSpec(work, inNetID, inIdx);

	OS_Printf("%d::ar,gr,hp,wsp,dsp,shotPw = %d,%d,%d,%d,%d,%d\n",
			inIdx,inData->ShotR[spec->Technique],inData->GardR[spec->Technique],inData->Stamina[spec->Stamina],
			inData->SpdW[spec->Speed], inData->SpdD[spec->Speed], inData->ShotPw[spec->Power]);

	outPoke->Param.ShotRange = inData->ShotR[spec->Technique];
	outPoke->Param.GardRange = inData->GardR[spec->Technique];
	outPoke->Param.StaminaMax = inData->Stamina[spec->Stamina];
	outPoke->Param.StaminaNow = inData->Stamina[spec->Stamina];
	outPoke->Param.MoveWalk = (inData->SpdW[spec->Speed] * FX32_ONE) / 10;	//<<<	1/10にして使用
	outPoke->Param.MoveDash = (inData->SpdD[spec->Speed] * FX32_ONE) / 10;	//<<<	1/10にして使用
	outPoke->Param.ShotPower = inData->ShotPw[spec->Power];
	outPoke->Param.Technique = spec->Technique;
	outPoke->Param.Power = spec->Power;
	outPoke->Param.Stamina = spec->Stamina;			//AI用
}

//----------レコードＢＭＰ---------------
//ＢＮＰウィンドウデータ
static const BMPWIN_DAT RecordBmpData = {
		REC_BG, WIN_REC_PX, WIN_REC_PY,
		WIN_REC_SX, WIN_REC_SY, REC_FONT_PAL, WIN_REC_CGX
};

static const BMPWIN_DAT NameBmpData[ENTRY_MEMBER_NUM_MAX] = {
	{
		NAME_BG, WIN_NAME1_PX, WIN_NAME_PY,
		WIN_NAME_SX, WIN_NAME_SY, SHOT_FONT_PAL, WIN_NAME1_CGX
	},
	{
		NAME_BG, WIN_NAME2_PX, WIN_NAME_PY,
		WIN_NAME_SX, WIN_NAME_SY, SHOT_FONT_PAL, WIN_NAME2_CGX
	},
	{
		NAME_BG, WIN_NAME3_PX, WIN_NAME_PY,
		WIN_NAME_SX, WIN_NAME_SY, SHOT_FONT_PAL, WIN_NAME3_CGX
	},
	{
		NAME_BG, WIN_NAME4_PX, WIN_NAME_PY,
		WIN_NAME_SX, WIN_NAME_SY, SHOT_FONT_PAL, WIN_NAME4_CGX
	},
};

//--------------------------------------------------------------------------------------------
/**
 * BMPウィンドウ追加
 *
 * @param 	ptr			コントローラポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CreateBmpWin( PKTHLN_SHOT_PTR ptr )
{
	int i;
	const BMPWIN_DAT * dat = &RecordBmpData;
	const BMPWIN_DAT * name_dat = NameBmpData;

	GF_BGL_BmpWinAddEx( ptr->bgl, &ptr->Win, dat );
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		GF_BGL_BmpWinAddEx( ptr->bgl, &ptr->NameWin[i], &name_dat[i] );
	}

	//先頭キャラをクリア（スクリーンクリアされてるところは、このキャラで埋まる）
	GF_BGL_CharFill( ptr->bgl, REC_BG, 0, 1, 0 );
	GF_BGL_CharFill( ptr->bgl, NAME_BG, 0, 1, 0 );

	//システムフォントパレット転送
	SystemFontPaletteLoad(PALTYPE_MAIN_BG, REC_FONT_PAL*32, ptr->HeapID);
	//シュートフォントパレット転送
	ArcUtil_PalSet( ARC_PKTHEV_SHOT, NARC_pkthev_shot_shot_font_nclr,
			PALTYPE_MAIN_BG, SHOT_FONT_PAL*32, 0x20, ptr->HeapID );
}

//----------------------------------------------------------------------------
/**
 *	@brief		レコード文字列展開
 *
 *	@param	ptr		コントローラポインタ
 *	@param	inPoint	得点
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetRecordStr(PKTHLN_SHOT_PTR ptr, const int inPoint)
{
	WORDSET *word;
	STRBUF * str;
	MSGDATA_MANAGER *msgman;
	int integer;

	GF_BGL_BmpWinDataFill( &ptr->Win, 0);

	//整数部分
	integer = inPoint;

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG, NARC_msg_pokethlon_dat, ptr->HeapID);
    word = WORDSET_Create(ptr->HeapID);
	WORDSET_RegisterNumber(word, 0, integer, 3,
				NUMBER_DISPTYPE_LEFT,NUMBER_CODETYPE_DEFAULT);

    str = MSGDAT_UTIL_AllocExpandString(word, msgman, msg_pkthln_new_record10, ptr->HeapID);

	GF_STR_PrintColor( 	&ptr->Win, FONT_TOUCH, str,
					0, 0, MSG_NO_PUT, COL_N_WHITE, NULL );
	STRBUF_Delete(str);//<一括表示なので、メモリをここで消してもOK
	WORDSET_Delete( word );
	MSGMAN_Delete( msgman );

	GF_BGL_BmpWinOn(&ptr->Win);
}

//----------------------------------------------------------------------------
/**
 *	@brief	壁あたり判定
 *
 *  @param	inNewPoint			新座標
 *  @param	inOldPoint			旧座標
 *  @param	inRange				範囲
 *  @param	inGlLineCheck		ゴールラインチェックするか？
 *	@param	outVec				交差座標格納バッファ
 *
 *	@return	HIT_CHECK			当たり結果
 */
//-----------------------------------------------------------------------------
static HIT_CHECK WallHitCheck(	const VecFx32 *inNewPoint, const VecFx32 *inOldPoint, const int inRange,
								const BOOL inGlLineCheck, VecFx32 *outVec	)
{
	Vec2DS32 w_srt, w_end, t_srt, t_end, cross;
	VecFx32 ws = {0,0,0};
	VecFx32 we = {0,0,0};
	VecFx32 w_cross;
	BOOL rc;
	u8 gl_idx;
	VecFx32 n;

	HIT_CHECK hit_check;
	u8 old_pos_hit;
	u8 goal_line_hit;

	VecFx32 g_vec1 = {0,0,0};
	VecFx32 g_vec2 = {0,0,0};
	VecFx32 n1 = { FX32_ONE,  FX32_ONE, 0};
	VecFx32 n2 = {-FX32_ONE,  FX32_ONE, 0};
	VecFx32 n3 = { FX32_ONE, -FX32_ONE, 0};
	VecFx32 n4 = {-FX32_ONE, -FX32_ONE, 0};

	outVec->x = 0;
	outVec->y = 0;
	outVec->z = 0;

	t_srt.x = inOldPoint->x / FX32_ONE;
	t_srt.y = inOldPoint->y / FX32_ONE;
	t_end.x = inNewPoint->x / FX32_ONE;
	t_end.y = inNewPoint->y / FX32_ONE;


	if (inNewPoint->y < (96+16)*FX32_ONE){		//画面上
		if (inNewPoint->x < 128*FX32_ONE){		//画面左
			//左上ゴールラインとの当たり判定を行う
			gl_idx = 0;
		}else{
			//右上ゴールラインとの当たり判定を行う
			gl_idx = 1;
		}
	}else{										//画面下
		if (inNewPoint->x < 128*FX32_ONE){		//画面左
			//左下ゴールラインとの当たり判定を行う
			gl_idx = 2;
		}else{
			//右下ゴールラインとの当たり判定を行う
			gl_idx = 3;
		}
	}

	hit_check = HIT_NONE;
	old_pos_hit = 0;
	goal_line_hit = 0;

	//ゴールラインとの当たり判定
	if (inGlLineCheck){
		switch(gl_idx){
		case 0:			//左上
			g_vec1.x = H_G1_X * FX32_ONE;
			g_vec1.y = H_G2_Y * FX32_ONE;
			g_vec2.x = H_G2_X * FX32_ONE;
			g_vec2.y = H_G1_Y * FX32_ONE;
			VEC_Normalize(&n1, &n);
			hit_check = HIT_G_LU;
			break;
		case 1:			//右上
			g_vec1.x = H_G3_X * FX32_ONE;
			g_vec1.y = H_G1_Y * FX32_ONE;
			g_vec2.x = H_G4_X * FX32_ONE;
			g_vec2.y = H_G2_Y * FX32_ONE;
			VEC_Normalize(&n2, &n);
			hit_check = HIT_G_RU;
			break;
		case 2:			//左下
			g_vec1.x = H_G2_X * FX32_ONE;
			g_vec1.y = H_G4_Y * FX32_ONE;
			g_vec2.x = H_G1_X * FX32_ONE;
			g_vec2.y = H_G3_Y * FX32_ONE;
			VEC_Normalize(&n3, &n);
			hit_check = HIT_G_LD;
			break;
		case 3:			//左下
			g_vec1.x = H_G4_X * FX32_ONE;
			g_vec1.y = H_G3_Y * FX32_ONE;
			g_vec2.x = H_G3_X * FX32_ONE;
			g_vec2.y = H_G4_Y * FX32_ONE;
			VEC_Normalize(&n4, &n);
			hit_check = HIT_G_RD;
			break;
		default:
			GF_ASSERT(0);
		}

		if ( hit_check != HIT_NONE ){
			VEC_MultAdd( inRange*FX32_ONE, &n, &g_vec1, &g_vec1);
			VEC_MultAdd( inRange*FX32_ONE, &n, &g_vec2, &g_vec2);

			w_srt.x = g_vec1.x / FX32_ONE;
			w_srt.y = g_vec1.y / FX32_ONE;
			w_end.x = g_vec2.x / FX32_ONE;
			w_end.y = g_vec2.y / FX32_ONE;

///			OS_Printf("%d,%d  %d,%d\n",w_srt.x,w_srt.y,w_end.x,w_end.y);

			rc = CheckCrossMatrix( &w_srt, &w_end, &t_srt, &t_end, &cross);
			if (rc){
///				OS_Printf("%d:ゴールラインヒット\n",gl_idx);
				if ( BG2D_VectorSideS32(&w_srt,&w_end,&cross) == 0){
///					OS_Printf("外側\n");
					*outVec = *inOldPoint;
					old_pos_hit = 1;
				}else{
					outVec->x = cross.x*FX32_ONE;
					outVec->y = cross.y*FX32_ONE;
				}
				goal_line_hit = 1;
			}else{
				hit_check = HIT_NONE;
			}
		}
	}

	//↓ここから壁との判定

	//ポケの現在座標がどの位置にあるかで、分岐
	if (inNewPoint->y < (96+16)*FX32_ONE){		//画面上

		//上の壁との当たり判定
		//半径分のオフセットつけてベクトル作成(コートがベクトル裏側になるように)
		if ( inNewPoint->y < (WALL_MIN_Y+inRange) * FX32_ONE ){
			if ( inOldPoint->y == (WALL_MIN_Y-inRange) * FX32_ONE ){
///				OS_Printf("上壁でストップ\n");
				*outVec = *inOldPoint;
				return HIT_U;
			}
		}
		ws.x = WALL_MIN_X * FX32_ONE;
		ws.y = (WALL_MIN_Y+inRange) * FX32_ONE;
		we.x = WALL_MAX_X * FX32_ONE;
		we.y = (WALL_MIN_Y+inRange) * FX32_ONE;
		rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
		if (rc){
			if (old_pos_hit){
///				OS_Printf("既にゴールラインにストップされている\n");
				return hit_check;
			}else{
///				OS_Printf("上壁にヒット\n");
				if (goal_line_hit){
					if (outVec->y >= w_cross.y){
						return hit_check;
					}
				}
				if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///					OS_Printf("移動の結果ゴールラインの中\n");
					*outVec = *inOldPoint;
					return HIT_U;
				}
				*outVec = w_cross;
				return HIT_U;
			}
		}

		if (inNewPoint->x < 128*FX32_ONE){	//画面左
			if ( inNewPoint->x < (WALL_MIN_X+inRange) * FX32_ONE ){
				if ( inOldPoint->x == (WALL_MIN_X+inRange) * FX32_ONE ){
///					OS_Printf("左壁でストップ\n");
					*outVec = *inOldPoint;
					return HIT_L;
				}
			}
			//左壁との当たり判定
			//半径分のオフセットつけてベクトル作成
			ws.x = (WALL_MIN_X+inRange) * FX32_ONE;
			ws.y = WALL_MAX_Y *FX32_ONE;
			we.x = (WALL_MIN_X+inRange) * FX32_ONE;
			we.y = WALL_MIN_Y * FX32_ONE;
			rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
			if (rc){
				if (old_pos_hit){
///					OS_Printf("既にゴールラインにストップされている\n");
					return hit_check;
				}else{
///					OS_Printf("左壁にヒット\n");
					if (goal_line_hit){
						if (outVec->x >= w_cross.x){
							return hit_check;
						}
					}
					if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///						OS_Printf("移動の結果ゴールラインの中\n");
						*outVec = *inOldPoint;
						return HIT_L;
					}
					*outVec = w_cross;
					return HIT_L;
				}
			}
		}else{	//画面右
			if ( inNewPoint->x > (WALL_MAX_X-inRange) * FX32_ONE ){
				if ( inOldPoint->x == (WALL_MAX_X-inRange) * FX32_ONE ){
///					OS_Printf("右壁でストップ\n");
					*outVec = *inOldPoint;
					return HIT_R;
				}
			}
			//右壁との当たり判定
			//半径分のオフセットつけてベクトル作成(コートがベクトル裏側になるように)
			ws.x = (WALL_MAX_X-inRange) * FX32_ONE;
			ws.y = WALL_MIN_Y * FX32_ONE;
			we.x = (WALL_MAX_X-inRange) * FX32_ONE;
			we.y = WALL_MAX_Y * FX32_ONE;
			rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
			if (rc){
				if (old_pos_hit){
///					OS_Printf("既にゴールラインにストップされている\n");
					return hit_check;
				}else{
///					OS_Printf("右壁にヒット\n");
					if (goal_line_hit){
						if (outVec->x <= w_cross.x){
							return hit_check;
						}
					}
					if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///						OS_Printf("移動の結果ゴールラインの中\n");
						*outVec = *inOldPoint;
						return HIT_R;
					}
					*outVec = w_cross;
					return HIT_R;
				}
			}
		}
	}else{		//画面下
		//下の壁との当たり判定
		//半径分のオフセットつけてベクトル作成(コートがベクトル裏側になるように)
		if ( inNewPoint->y > (WALL_MAX_Y-inRange) * FX32_ONE ){
			if ( inOldPoint->y == (WALL_MAX_Y-inRange) * FX32_ONE ){
///				OS_Printf("下壁でストップ\n");
				*outVec = *inOldPoint;
				return HIT_D;
			}
		}
		ws.x = WALL_MAX_X * FX32_ONE;
		ws.y = (WALL_MAX_Y-inRange) * FX32_ONE;
		we.x = WALL_MIN_X * FX32_ONE;
		we.y = (WALL_MAX_Y-inRange) * FX32_ONE;
		rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
		if (rc){
			if (old_pos_hit){
///				OS_Printf("既にゴールラインにストップされている\n");
				return hit_check;
			}else{
///				OS_Printf("下壁にヒット\n");
				if (goal_line_hit){
					if (outVec->y <= w_cross.y){
						return hit_check;
					}
				}
				if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///					OS_Printf("移動の結果ゴールラインの中\n");
					*outVec = *inOldPoint;
					return HIT_D;
				}
				*outVec = w_cross;
				return HIT_D;
			}
		}

		if (inNewPoint->x < 128*FX32_ONE){		//画面左
			if ( inNewPoint->x < (WALL_MIN_X+inRange) * FX32_ONE ){
				if ( inOldPoint->x == (WALL_MIN_X+inRange) * FX32_ONE ){
///					OS_Printf("左壁でストップ\n");
					*outVec = *inOldPoint;
					return HIT_L;
				}
			}
			//左壁との当たり判定
			//半径分のオフセットつけてベクトル作成
			ws.x = (WALL_MIN_X+inRange) * FX32_ONE;
			ws.y = WALL_MAX_Y *FX32_ONE;
			we.x = (WALL_MIN_X+inRange) * FX32_ONE;
			we.y = WALL_MIN_Y * FX32_ONE;
			rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
			if (rc){
				if (old_pos_hit){
///					OS_Printf("既にゴールラインにストップされている\n");
					return hit_check;
				}else{
///					OS_Printf("左壁にヒット\n");
					if (goal_line_hit){
						if (outVec->x >= w_cross.x){
							return hit_check;
						}
					}

					if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///						OS_Printf("移動の結果ゴールラインの中\n");
						*outVec = *inOldPoint;
						return HIT_L;
					}
					*outVec = w_cross;
					return HIT_L;
				}
			}
		}else{
			if ( inNewPoint->x > (WALL_MAX_X-inRange) * FX32_ONE ){
				if ( inOldPoint->x == (WALL_MAX_X-inRange) * FX32_ONE ){
///					OS_Printf("右壁でストップ\n");
					*outVec = *inOldPoint;
					return HIT_R;
				}
			}
			//右壁との当たり判定
			//半径分のオフセットつけてベクトル作成(コートがベクトル裏側になるように)
			ws.x = (WALL_MAX_X-inRange) * FX32_ONE;
			ws.y = WALL_MIN_Y * FX32_ONE;
			we.x = (WALL_MAX_X-inRange) * FX32_ONE;
			we.y = WALL_MAX_Y * FX32_ONE;
			rc = CheckCorssWall(&ws, &we, inOldPoint, inNewPoint, &w_cross);
			if (rc){
				if (old_pos_hit){
///					OS_Printf("既にゴールラインにストップされている\n");
					return hit_check;
				}else{
///					OS_Printf("右壁にヒット\n");
					if (goal_line_hit){
						if (outVec->x <= w_cross.x){
							return hit_check;
						}
					}
					if ( inGlLineCheck && CheckCrossAfter( &w_srt, &w_end, &t_srt, &w_cross) ){
///						OS_Printf("移動の結果ゴールラインの中\n");
						*outVec = *inOldPoint;
						return HIT_R;
					}
					*outVec = w_cross;
					return HIT_R;
				}
			}
		}
	}

	return hit_check;
}

//----------------------------------------------------------------------------
/**
 *	@brief	移動後のライン交差判定
 *
 *	@param		w_str		開始座標1
 *	@param		w_end		終端座標1
 *	@param		t_srt		開始座標2
 *	@param		t_end		終端座標2
 *
 *	@return	BOOL			TRUEで交差している
 */
//-----------------------------------------------------------------------------
static BOOL CheckCrossAfter(Vec2DS32 *w_srt, Vec2DS32 *w_end,
		Vec2DS32 *t_srt, VecFx32 *end)
{
	Vec2DS32 t_end, cross;
	t_end.x = end->x /FX32_ONE;
	t_end.y = end->y /FX32_ONE;

	return CheckCrossMatrix( w_srt, w_end, t_srt, &t_end, &cross);
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボールの方向補正
 *
 *	@param		ptr			競技ポインタ
 *	@param		inDirVec	方向ベクトル
 *
 *	@return	VecFX32			補正後の方向ベクトル
 */
//-----------------------------------------------------------------------------
static VecFx32 FixBallDir(PKTHLN_SHOT_PTR ptr, const VecFx32 *inDirVec )
{
	fx32 cos,sin;
	VecFx32 vec;
	cos = GetCos( &ptr->BallBaseDir[0], inDirVec );
	sin = GetSin( &ptr->BallBaseDir[0], inDirVec );

	if (cos >= FX_CosIdx(0x1000)){			//X軸方向+
		vec = ptr->BallBaseDir[0];
	}else if (cos <= -FX_CosIdx(0x1000)){	//X軸方向-
		vec = ptr->BallBaseDir[1];
	}else if (sin >= FX_SinIdx(0x3000)){	//Y軸方向+
		vec = ptr->BallBaseDir[2];
	}else if (sin <= -FX_SinIdx(0x3000)){	//Y軸方向-
		vec = ptr->BallBaseDir[3];
	}else if ( (cos > 0)&&(sin > 0) ){		//X軸+Y軸+
		vec = ptr->BallBaseDir[4];
	}else if ( (cos < 0)&&(sin > 0) ){		//X軸-Y軸+
		vec = ptr->BallBaseDir[5];
	}else if ( (cos > 0)&&(sin < 0) ){		//X軸+Y軸-
		vec = ptr->BallBaseDir[6];
	}else if ( (cos < 0)&&(sin < 0) ){		//X軸-Y軸-
		vec = ptr->BallBaseDir[7];
	}else{
		GF_ASSERT(0);
		vec = *inDirVec;
	}

	return vec;
}

//----------------------------------------------------------------------------
/**
 *	@brief	壁との交差判定
 *
 *	@param		inWsVec		壁開始位置ベクトル
 *	@param		inWeVec		壁終了位置ベクトル
 *	@param		inTsVec		指定開始位置ベクトル
 *	@param		inTeVec		指定終了位置ベクトル
 *	@param		outCross	交点
 *
 *	@return	BOOL			TRUEでヒット
 */
//-----------------------------------------------------------------------------
static BOOL CheckCorssWall(const VecFx32 *inWsVec, const VecFx32 *inWeVec,
		const VecFx32 *inTsVec, const VecFx32 *inTeVec, VecFx32 *outCross)
{
	VecFx32 vec = {0,0,0};

	VecFx32 dir_vec;
	fx32 len1, len2, t;
	Vec2DS32 vector1_s, vector1_e, vector2_s, vector2_e;

	vector1_s.x = inWsVec->x / FX32_ONE;
	vector1_s.y = inWsVec->y / FX32_ONE;
	vector1_e.x = inWeVec->x / FX32_ONE;
	vector1_e.y = inWeVec->y / FX32_ONE;
	vector2_s.x = inTsVec->x / FX32_ONE;
	vector2_s.y = inTsVec->y / FX32_ONE;
	vector2_e.x = inTeVec->x / FX32_ONE;
	vector2_e.y = inTeVec->y / FX32_ONE;

	// ベクトル範囲内に交点があるのかチェック
	if( BG2D_CheckSegmentToSegmentS32( &vector1_s, &vector1_e,
							&vector2_s, &vector2_e ) == FALSE ){
		// 交点はありません
		return FALSE;
	}

	//方向ベクトル
	VEC_Subtract( inWeVec, inWsVec, &dir_vec );
	//正規化
	VEC_Normalize(&dir_vec, &dir_vec);

	//垂直・水平方向で分岐
	if ( inWsVec->y == inWeVec->y ){				//水平
		fx32 wall_y;
		wall_y = inWsVec->y;
		//壁と始点座標との距離Aを求める
		len1 = wall_y - inTsVec->y;
		if (len1 < 0){
			len1 *= -1;
		}
		//壁と終点座標との距離Bを求める
		len2 = wall_y - inTeVec->y;
		if (len2 < 0){
			len2 *= -1;
		}
		if (len2 == 0){
			return FALSE;
		}
		//壁ベクトルへ始点座標からおろした垂線の交点を出す（開始位置ベクトル）
		vec.x = inTsVec->x;
		vec.y = wall_y;
		//交点は内分点なので、開始位置ベクトル+壁方向ベクトルｘ距離A　/（距離A+距離B）
		t  = FX_Div(len1, len1+len2);
		VEC_MultAdd( t, &dir_vec, &vec, outCross);
		return TRUE;
	}else if(inWsVec->x == inWeVec->x) {				//垂直
		fx32 wall_x;
		wall_x = inWsVec->x;
		//壁と始点座標との距離Aを求める
		len1 = wall_x - inTsVec->x;
		if (len1 < 0){
			len1 *= -1;
		}
		//壁と終点座標との距離Bを求める
		len2 = wall_x - inTeVec->x;
		if (len2 < 0){
			len2 *= -1;
		}
		if (len2 == 0){
			return FALSE;
		}
		//壁ベクトルへ始点座標からおろした垂線の交点を出す（開始位置ベクトル）
		vec.x = wall_x;
		vec.y = inTsVec->y;
		//交点は内分点なので、開始位置ベクトル+壁方向ベクトルｘ距離A　/（距離A+距離B）
		t  = FX_Div(len1, len1+len2);
		VEC_MultAdd( t, &dir_vec, &vec, outCross);
		return TRUE;
	}else {
		GF_ASSERT(0);
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール生成
 *
 *	@param		ptr		コントローラポインタ
 *	@param		ball		ボールポインタ
 *
 *	@return		none
 */
//-----------------------------------------------------------------------------
static void GenerateBall(PKTHLN_SHOT_PTR ptr, SHOT_BALL *ball)
{
	int i;
	u8 idx;
	u8 pos_idx;
	u8 gene_pos[BALL_GENE_POS_NUM];
	u8 count = 0;
	//生成場所候補を算出
	for (i=0;i<BALL_GENE_POS_NUM;i++){
		if ( (ptr->Ball[0].GeneIdx != i)&&(ptr->Ball[1].GeneIdx != i) ){
			//エントリ
			gene_pos[count++] = i;
		}
	}
	//エントリされたところから1つ選出
	idx = gf_rand()%count;
	pos_idx = gene_pos[idx];

	ball->Pos.x = BallGenePos[pos_idx].X * FX32_ONE;
	ball->Pos.y = BallGenePos[pos_idx].Y * FX32_ONE;
	//生成した場所を記憶
	ball->GeneIdx = pos_idx;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール出現演出を加味した通信Y座標のセット
 *
 *	@param		ball		ボールポインタ
 *
 *	@return		none
 */
//-----------------------------------------------------------------------------
static u8 GetCommBallY(SHOT_BALL *ball)
{
	int y;
	//ボールが準備状態か？
	if (ball->State == BALL_STATE_READY){			//準備状態
		//ボール基本Y座標で分岐
		if(ball->Pos.y == 11*8*FX32_ONE){
			y = 192 + ball->AppCount;
		}else if(ball->Pos.y == 13*8*FX32_ONE){
			y = 200 + ball->AppCount;
		}else if(ball->Pos.y == 15*8*FX32_ONE){
			y = 208 + ball->AppCount;
		}else{
			GF_ASSERT(0);
			y = ball->Pos.y / FX32_ONE;
		}
	}else if(ball->State == BALL_STATE_GOAL){		//ゴール状態
		u8 goal_idx;
		if (ball->Owner == SHOT_EVENT_POKE_NUM){
			y = ball->Pos.y / FX32_ONE;
		}else{
			goal_idx = GetGoalIdx(ball);
			//ゴールエフェクト用ボール座標を算出
			y = CalcGallEffBallY(goal_idx, ball->Owner/ENTRY_MAX);
		}
	}else{
		y = ball->Pos.y / FX32_ONE;
	}
	return y;
}

//----------------------------------------------------------------------------
/**
 *	@brief	通信で送られてきたボールY座標を表示Y座標に変更
 *
 *	@param		inY
 *
 *	@return		表示Y座標
 */
//-----------------------------------------------------------------------------
static fx32 GetBallDispY(int inY)
{
	if (inY < BALL_FIELD){
		return inY * FX32_ONE;
	}else if (inY < BALL_BOUND){
		int y;
		int base;
		u8 frame;
		OS_Printf("ボール出現中\n");
		base = (inY - BALL_FIELD);
		frame = base%BALL_APP_COUNT;	//0〜7
		if (base < 8){
			y = ( 11*8 + BallAppOfs[frame] );
		}else if(base < 16){
			y = ( 13*8 + BallAppOfs[frame] );
		}else{	//base < 24
			y = ( 15*8 + BallAppOfs[frame] );
		}
		return y*FX32_ONE;
	}else if(inY < BALL_GOAL){
		return inY * FX32_ONE;
	}else{
		GF_ASSERT(0);
	}
	return inY * FX32_ONE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ダメージ中のスピン
 *
 *	@param		shot_poke		ポケモン
 *
 *	@return		none
 */
//-----------------------------------------------------------------------------
static void UpdateDamageSpin(SHOT_POKE* shot_poke)
{
	switch(shot_poke->Dir){
	case POKE_DIR_UP:
		shot_poke->Dir = POKE_DIR_RIGHT;
		break;
	case POKE_DIR_RIGHT:
		shot_poke->Dir = POKE_DIR_DOWN;
		break;
	case POKE_DIR_DOWN:
		shot_poke->Dir = POKE_DIR_LEFT;
		break;
	case POKE_DIR_LEFT:
		shot_poke->Dir = POKE_DIR_UP;
		break;
	}
}

//----------------------------------------------------------------------------
/**
 *	@briefボール出現音再生
 *
 *	@param		ptr			ワークポインタ
 *	@param		inBallIdx	ボールインデックス0〜1
 *	@param		inIsGold	金玉フラグ
 *	@param		inY			通信Y座標
 *
 *	@return		none
 */
//-----------------------------------------------------------------------------
static void PlayBallAppSE(PKTHLN_SHOT_PTR ptr, const u8 inBallIdx, const u8 inIsGold, const int inY)
{
	if (inY < BALL_FIELD){
		//フラグクリア
		ptr->BallAppSeFlg[inBallIdx] = 0;
		return ;
	}else if(inY < BALL_BOUND){
		if ( !ptr->BallAppSeFlg[inBallIdx] ){
			ptr->BallAppSeFlg[inBallIdx] = 1;		//フラグセット
			if ( (inBallIdx==0)&&inIsGold ){			//金玉
				Snd_SePlay( SE_BOUND_SUPER_BALL );
			}else{										//ノーマル
				Snd_SePlay( SE_BOUND_NORMAL_BALL );
			}
		}
		return;
	}
	//フラグクリア
	ptr->BallAppSeFlg[inBallIdx] = 0;
}

//----------------------------------------------------------------------------
/**
 *	@brief		名前・ゴール文字列表示
 *
 *	@param	ptr			ワークポインタ
 *	@param	inNetID		ネットID
 *	@param	inGoal	ゴールしたか？	GOAL_TYPE参照
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void WriteNameStr(PKTHLN_SHOT_PTR ptr, const u8 inNetID, const GOAL_TYPE inGoal)
{
	GF_BGL_BmpWinDataFill( &ptr->NameWin[inNetID], 0);

	if (inGoal != GOAL_NONE){
		STRBUF *str;
		if (inGoal == GOAL_NORMAL){
			str = ptr->GoalStr;
		}else if(inGoal == GOAL_GOLD){
			str = ptr->Goal2Str;
		}else if(inGoal == GOAL_MINUS){
			str = ptr->LostStr;
		}else{
			GF_ASSERT(0);
			str = ptr->GoalStr;
		}
		//ゴール数値表示
		GF_STR_PrintColor( 	&ptr->NameWin[inNetID], FONT_TOUCH, str,
							0, 0, MSG_NO_PUT, COL_SHOT_WHITE, NULL );
	}else{
		GF_PRINTCOLOR col;
		if (ptr->TopFlg[inNetID]){
			col = COL_SHOT_ORANGE;
		}else{
			col = COL_SHOT_WHITE;
		}
		//プレーヤ名表示
		GF_STR_PrintColor( 	&ptr->NameWin[inNetID], FONT_TOUCH, ptr->PlayerStr[inNetID],
							0, 0, MSG_NO_PUT, col, NULL );
	}

	GF_BGL_BmpWinOn(&ptr->NameWin[inNetID]);
}

//----------------------------------------------------------------------------
/**
 *	@brief		名前/ゴール文字列作成
 *
 *	@param	work		ポケスロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MakePlayerGoalStr(PKTHLN_PTR work)
{
	u8 i;
	PKTHLN_SHOT_PTR ptr;

	WORDSET *word;
	STRBUF * str;
	MSGDATA_MANAGER *msgman;

	ptr = (PKTHLN_SHOT_PTR)PTFrame_GetEventWorkPtr(work);
	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG, NARC_msg_pokethlon_dat, ptr->HeapID);
    word = WORDSET_Create(ptr->HeapID);

	//ゴール文字列作成
	ptr->GoalStr = MSGMAN_AllocString(msgman, msg_pkthln_shot02);
	ptr->Goal2Str = MSGMAN_AllocString(msgman, msg_pkthln_shot03);
	ptr->LostStr = MSGMAN_AllocString(msgman, msg_pkthln_shot04);

	//プレーヤー名作成
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		STRBUF *name_buf;
		//マイステータスにアクセスして名前取得
		name_buf = MyStatus_CreateNameString(
				PTFrame_GetMyStatus(work, i),
				ptr->HeapID);
		WORDSET_RegisterWord( word, 0, name_buf, PM_NEUTRAL, TRUE, PM_LANG );
		ptr->PlayerStr[i] = MSGDAT_UTIL_AllocExpandString(word, msgman, msg_pkthln_shot01, ptr->HeapID);
		STRBUF_Delete(name_buf);
	}
	WORDSET_Delete( word );
	MSGMAN_Delete( msgman );
}

//----------------------------------------------------------------------------
/**
 *	@brief		名前/ゴール文字列削除
 *
 *	@param	work		ポケスロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DelPlayerGoalStr(PKTHLN_PTR work)
{
	u8 i;
	PKTHLN_SHOT_PTR ptr;

	ptr = (PKTHLN_SHOT_PTR)PTFrame_GetEventWorkPtr(work);

	STRBUF_Delete(ptr->GoalStr);
	STRBUF_Delete(ptr->Goal2Str);
	STRBUF_Delete(ptr->LostStr);
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		STRBUF_Delete(ptr->PlayerStr[i]);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief		ゴールしたときの演出用タスクのセットアップ
 *
 *	@param	ptr		ワークポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetupGoalEffTcb(PKTHLN_SHOT_PTR ptr)
{
	u8 i;
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		GOAL_EFF * eff = &(ptr->GoalEff[i]);
		eff->Seq = GOAL_EFF_WAIT;
		eff->NetID = i;
		eff->Counter = 0;
		eff->BallIdx = -1;
		eff->ptr = ptr;
		eff->GoalEffTcbPtr = TCB_Add(GoalEffTcb, eff, GOAL_EFF_TCB_PRI);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief		ゴールしたときの演出用タスクの削除
 *
 *	@param	ptr		ワークポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void DelGoalEffTcb(PKTHLN_SHOT_PTR ptr)
{
	u8 i;
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		GOAL_EFF * eff = &(ptr->GoalEff[i]);
		TCB_Delete(eff->GoalEffTcbPtr);
	}
}


//----------------------------------------------------------------------------
/**
 *	@brief		ゴールしたときの演出用タスクへ演出リクエスト
 *
 *	@param	ptr			ワークポインタ
 *	@param	inIdx		プレーヤーインデックス
 *	@param	inIsPlus	加算か？
 *	@param	inIsGold	金玉？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void ReqGoalEff(PKTHLN_SHOT_PTR ptr, const u8 inIdx, const u8 inIsPlus, const u8 inIsGold)
{
	ptr->GoalEff[inIdx].Seq = GOAL_EFF_START;
	ptr->GoalEff[inIdx].IsPlus = inIsPlus;
	ptr->GoalEff[inIdx].IsGold = inIsGold;
}

//----------------------------------------------------------------------------
/**
 *	@brief		ゴールしたときの演出用タスク
 *
 *	@param	work		ポケスロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void GoalEffTcb(TCB_PTR tcb, void* work)
{
	GOAL_EFF * eff = (GOAL_EFF *)work;

	switch(eff->Seq){
	case GOAL_EFF_WAIT:
		break;
	case GOAL_EFF_START:
		if (eff->IsPlus){
			if (eff->IsGold){
				//ウィンドウを「+2」にする
				WriteNameStr(eff->ptr, eff->NetID, GOAL_GOLD);
			}else{
				//ウィンドウを「+1」にする
				WriteNameStr(eff->ptr, eff->NetID, GOAL_NORMAL);
			}
		}else{
			//ウィンドウを「-1」にする
			WriteNameStr(eff->ptr, eff->NetID, GOAL_MINUS);
		}
		//カウンターを0に
		eff->Counter = 0;
		//パレット関連初期化
		eff->PalNo = 0;
		eff->FlshCnt = 0;
		//次のシーケンス
		eff->Seq = GOAL_EFF_FLASH;
		break;
	case GOAL_EFF_FLASH:
		eff->Counter++;
		if (eff->Counter>GOAL_EFF_FRAME){
			//点滅終了　元のパレットへ
			GF_BGL_ScrPalChange( eff->ptr->bgl, GF_BGL_FRAME1_M,
				PAL_CHG_OFS*eff->NetID, 0, PAL_CHG_W, PAL_CHG_H, BG_PAL_FRAME );
			GF_BGL_LoadScreenV_Req(eff->ptr->bgl, GF_BGL_FRAME1_M);
			//ウィンドウをプレーヤー名に
			WriteNameStr(eff->ptr, eff->NetID, GOAL_NONE);
			//ボールインデックス初期化
			eff->BallIdx = -1;
			//終了　シーケンスを待ち状態に
			eff->Seq = GOAL_EFF_WAIT;
			break;
		}
		//点滅
		if (eff->FlshCnt == 0){
			u8 pal_idx;
			u8 plus_pal[2] = {BG_PAL_FRAME,BG_PAL_PLUS};		//プラスのときのパレットインデックス
			u8 minus_pal[2] = {BG_PAL_FRAME,BG_PAL_MINUS};	//マイナスのときのパレットインデックス
			eff->PalNo = (eff->PalNo+1)%2;
			eff->FlshCnt = FLASH_MARGINE;
			if (eff->IsPlus){			//プラス
				pal_idx = plus_pal[eff->PalNo];
			}else{			//マイナス
				pal_idx = minus_pal[eff->PalNo];
			}
			GF_BGL_ScrPalChange( eff->ptr->bgl, GF_BGL_FRAME1_M,
				PAL_CHG_OFS*eff->NetID, 0, PAL_CHG_W, PAL_CHG_H, pal_idx );
			GF_BGL_LoadScreenV_Req(eff->ptr->bgl, GF_BGL_FRAME1_M);
		}else{
			eff->FlshCnt--;
		}
		break;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief		ゴールしたときの演出時ボール座標計算
 *
 *	@param	inGoalIdx		ゴールインデックス
 *	@param	inOwnerPlayer	ボールオーナー
 *
 *	@return	y				Ｙ座標
 */
//-----------------------------------------------------------------------------
static const u8 CalcGallEffBallY(const u8 inGoalIdx, const u8 inOwnerPlayer)
{
	u8 base, y;
	//ゴールインデックスによる分岐
	switch(inGoalIdx){
	case 0:
		base = GOAL_EFF_BASE_Y1;
		break;
	case 1:
		base = GOAL_EFF_BASE_Y2;
		break;
	case 2:
		base = GOAL_EFF_BASE_Y3;
		break;
	case 3:
		base = GOAL_EFF_BASE_Y4;
		break;
	default:
		GF_ASSERT(0);
		return 0;
	}

	if (inOwnerPlayer >= ENTRY_MEMBER_NUM_MAX){
		GF_ASSERT(0);
		return 0;
	}

	//ボール所有者によるベース加算
	y = base + inOwnerPlayer;

	return y;
}

//----------------------------------------------------------------------------
/**
 *	@brief		ボールの位置からゴールインデックス取得
 *
 *	@param	inBall			ボール
 *
 *	@return goal_idx		ゴールインデックス
 */
//-----------------------------------------------------------------------------
static const u8 GetGoalIdx(const SHOT_BALL * inBall)
{
	u8 goal_idx;
	//どこの象限にあるかを調べる
	goal_idx = GetGoalIdxByXY(inBall->Pos.x/FX32_ONE, inBall->Pos.y/FX32_ONE);
	return goal_idx;
}

//----------------------------------------------------------------------------
/**
 *	@brief		整数座標からゴールインデックス取得
 *
 *	@param	inX
 *	@param	inY
 *
 *	@return goal_idx		ゴールインデックス
 */
//-----------------------------------------------------------------------------
static const u8 GetGoalIdxByXY(const int inX, const int inY)
{
	u8 goal_idx;
	if (inX < 128 ){
		if (inY < 96+16){	//左上
			goal_idx = 0;
		}else{								//左下
			goal_idx = 2;
		}
	}else{
		if (inY < 96+16 ){	//右上
			goal_idx = 1;
		}else{								//右下
			goal_idx = 3;
		}
	}

	return goal_idx;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ストックスコアを見て、トップかどうかを判定する
 *
 *	@param	ptr			競技ポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static const void SetTopFlg(PKTHLN_SHOT_PTR ptr)
{
	u8 top = 0;
	u8 i;

	if ( ptr->Timer <= TOP_NON_DISP_TIME ){
		for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			ptr->TopFlg[i] = 0;
		}
		return;
	}

	//トップのスコアを調べる
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		if (top < ptr->ScoreStoc[i]){
			top = ptr->ScoreStoc[i];
		}
	}

	//トップのプレーヤーを判定する
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		if ((top != 0) && (top == ptr->ScoreStoc[i])){
			ptr->TopFlg[i] = 1;
		}else{
			ptr->TopFlg[i] = 0;
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	プレーヤー名を描画
 *
 *	@param	ptr		競技ポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void PrintPlayerName(PKTHLN_SHOT_PTR ptr)
{
	u8 i;
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		GOAL_EFF * eff = &(ptr->GoalEff[i]);
		//演出タスクが稼動している場合はプリントしない
		if (eff->Seq == GOAL_EFF_WAIT){
			WriteNameStr(ptr, i, GOAL_NONE);
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	自分のポケのプライオリティソート
 *
 *	@param	my_poke		自分のポケモンポインタ配列
 *	@param	inMyPosY	Y座標配列
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SortPpkePriority(SHOT_POKE *my_poke, u8 *inMyPokeY)
{
	MY_POKE_SORT data[ENTRY_MAX];
	MY_POKE_SORT *sort[ENTRY_MAX];
	MY_POKE_SORT *tmp_top;
	MY_POKE_SORT *tmp_next;
	u8 i;

	//データ作成
	for (i=0;i<ENTRY_MAX;i++){
		data[i].PosY = &inMyPokeY[i];
		data[i].Poke = &my_poke[i];
	}

	//Yソートする
	if ( *data[0].PosY >= *data[1].PosY ){
		tmp_top = &data[0];
		tmp_next = &data[1];
	}else{
		tmp_top = &data[1];
		tmp_next = &data[0];
	}

	if (*tmp_top->PosY >= *data[2].PosY){
		if (*tmp_next->PosY >= *data[2].PosY){
			//確定
			sort[0] = tmp_top;
			sort[1] = tmp_next;
			sort[2] = &data[2];
		}else{
			//確定
			sort[0] = tmp_top;
			sort[1] = &data[2];
			sort[2] = tmp_next;
		}
	}else{
		//確定
		sort[0] = &data[2];
		sort[1] = tmp_top;
		sort[2] = tmp_next;
	}

	//ソートした順にプライオリティ決定
	for(i=0;i<ENTRY_MAX;i++){
		PokeAct_SetPriority(sort[i]->Poke->PokeActPtr, PRI_POKE_MINE+i);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * ソート用比較関数
 *
 * @param	elem1		要素1
 * @param	elem2		要素2
 * @return	s32
 */
//--------------------------------------------------------------------------------------------
static s32 CompFunc(void *elem1, void *elem2)
{
	s32 ret;
	POKE_SORT_WORK * poke1 = elem1;
	POKE_SORT_WORK * poke2 = elem2;
	if (poke1->Y > poke2->Y){		//要素1の方がY値が高い場合は要素1を前に
		ret = -1;		//要素1が前
	}else if( poke1->Y < poke2->Y ){	//要素2の方がY値が高い場合は要素2を前に
		ret = 1;		//要素2が後
	}else{	//Yの値が同じ場合、割り振られたインデックスの小さい方を優先するようにする
		if (poke1->Idx < poke2->Idx){
			ret = -1;
		}else if(poke1->Idx > poke2->Idx){
			ret = 1;
		}else {
			//※NitroSDKのソート関数のコールバックは自分自身の比較もしているようなので、ここにアサートがあるととまってしまう
			ret = 0;
		}
	}
	return ret;
}

//--------------------------------------------------------------------------------------------
/**
 * 他チームポケソート関数
 *
 * @param	ptr			競技ポインタ
 * @param	parent		受信通信データ
 * @param	inMyNetID	自分のネットID
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SortEnemyPoke(PKTHLN_SHOT_PTR ptr, SHOT_PARENT_DATA *parent, const u8 inMyNetID)
{
	u8 i;
	u32 size;
	u8 idx;
	u8 total_poke_num;
	POKE_SORT_WORK sort_work[SORT_POKE_MAX];
	idx = 0;
	total_poke_num = ENTRY_MAX*ENTRY_MEMBER_NUM_MAX;
	for (i=0;i<total_poke_num;i++){
		if ((i/ENTRY_MAX) == inMyNetID){	//自分のポケは対象外
			continue;
		}
		sort_work[idx].Idx = i;
		sort_work[idx].Y = parent->PokeY[i];
		idx++;
	}
	size = sizeof(POKE_SORT_WORK);

	MATH_QSort( sort_work,
			    SORT_POKE_MAX,
				size,
				CompFunc,
				ptr->PokeSortBuf );

	for (i=0;i<SORT_POKE_MAX;i++){
		SHOT_POKE *shot_poke;
		u8 idx;
		idx = sort_work[i].Idx;
		shot_poke = &ptr->Poke[idx/ENTRY_MAX][idx%ENTRY_MAX];
		PokeAct_SetPriority(shot_poke->PokeActPtr, PRI_POKE+i);
	}
}

//--------------------------------------------------------------------------------------------
/**
 * レコードコールバック関数
 *
 * @param	work		ポケスロンワークポインタ
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void RecCallBack(PKTHLN_PTR work)
{
	COMM_EVENT_COMMON_DATA * data;
	SHOT_PARENT_DATA *parent;
	PKTHLN_SHOT_PTR ptr;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	ptr = PTFrame_GetEventWorkPtr(work);

	//ニューレコード用にレコードをセット
	{
		u8 point;
		point = ShotSub_GetDispScore(ptr->SubDispCntPtr);
		//フレームワークにニューレコードチェック用のレコード値をセット
		PTFrame_SetCheckRecord(work, point);
		SetRecordStr(ptr, point);
	}
}
